diff nss/lib/ckfw/wrap.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/ckfw/wrap.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,5672 @@
+/* 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/. */
+
+/*
+ * wrap.c
+ *
+ * This file contains the routines that actually implement the cryptoki
+ * API, using the internal APIs of the NSS Cryptoki Framework.  There is
+ * one routine here for every cryptoki routine.  For linking reasons
+ * the actual entry points passed back with C_GetFunctionList have to
+ * exist in one of the Module's source files; however, those are merely
+ * simple wrappers that call these routines.  The intelligence of the
+ * implementations is here.
+ */
+
+#ifndef CK_T
+#include "ck.h"
+#endif /* CK_T */
+
+/*
+ * NSSCKFWC_Initialize
+ * NSSCKFWC_Finalize
+ * NSSCKFWC_GetInfo
+ * -- NSSCKFWC_GetFunctionList -- see the API insert file
+ * NSSCKFWC_GetSlotList
+ * NSSCKFWC_GetSlotInfo
+ * NSSCKFWC_GetTokenInfo
+ * NSSCKFWC_WaitForSlotEvent
+ * NSSCKFWC_GetMechanismList
+ * NSSCKFWC_GetMechanismInfo
+ * NSSCKFWC_InitToken
+ * NSSCKFWC_InitPIN
+ * NSSCKFWC_SetPIN
+ * NSSCKFWC_OpenSession
+ * NSSCKFWC_CloseSession
+ * NSSCKFWC_CloseAllSessions
+ * NSSCKFWC_GetSessionInfo
+ * NSSCKFWC_GetOperationState
+ * NSSCKFWC_SetOperationState
+ * NSSCKFWC_Login
+ * NSSCKFWC_Logout
+ * NSSCKFWC_CreateObject
+ * NSSCKFWC_CopyObject
+ * NSSCKFWC_DestroyObject
+ * NSSCKFWC_GetObjectSize
+ * NSSCKFWC_GetAttributeValue
+ * NSSCKFWC_SetAttributeValue
+ * NSSCKFWC_FindObjectsInit
+ * NSSCKFWC_FindObjects
+ * NSSCKFWC_FindObjectsFinal
+ * NSSCKFWC_EncryptInit
+ * NSSCKFWC_Encrypt
+ * NSSCKFWC_EncryptUpdate
+ * NSSCKFWC_EncryptFinal
+ * NSSCKFWC_DecryptInit
+ * NSSCKFWC_Decrypt
+ * NSSCKFWC_DecryptUpdate
+ * NSSCKFWC_DecryptFinal
+ * NSSCKFWC_DigestInit
+ * NSSCKFWC_Digest
+ * NSSCKFWC_DigestUpdate
+ * NSSCKFWC_DigestKey
+ * NSSCKFWC_DigestFinal
+ * NSSCKFWC_SignInit
+ * NSSCKFWC_Sign
+ * NSSCKFWC_SignUpdate
+ * NSSCKFWC_SignFinal
+ * NSSCKFWC_SignRecoverInit
+ * NSSCKFWC_SignRecover
+ * NSSCKFWC_VerifyInit
+ * NSSCKFWC_Verify
+ * NSSCKFWC_VerifyUpdate
+ * NSSCKFWC_VerifyFinal
+ * NSSCKFWC_VerifyRecoverInit
+ * NSSCKFWC_VerifyRecover
+ * NSSCKFWC_DigestEncryptUpdate
+ * NSSCKFWC_DecryptDigestUpdate
+ * NSSCKFWC_SignEncryptUpdate
+ * NSSCKFWC_DecryptVerifyUpdate
+ * NSSCKFWC_GenerateKey
+ * NSSCKFWC_GenerateKeyPair
+ * NSSCKFWC_WrapKey
+ * NSSCKFWC_UnwrapKey
+ * NSSCKFWC_DeriveKey
+ * NSSCKFWC_SeedRandom
+ * NSSCKFWC_GenerateRandom
+ * NSSCKFWC_GetFunctionStatus
+ * NSSCKFWC_CancelFunction
+ */
+
+/* figure out out locking semantics */
+static CK_RV
+nssCKFW_GetThreadSafeState(CK_C_INITIALIZE_ARGS_PTR pInitArgs,
+                           CryptokiLockingState *pLocking_state) {
+  int functionCount = 0;
+
+  /* parsed according to (PKCS #11 Section 11.4) */
+  /* no args, the degenerate version of case 1 */
+  if (!pInitArgs) {
+    *pLocking_state = SingleThreaded;
+    return CKR_OK;
+  } 
+
+  /* CKF_OS_LOCKING_OK set, Cases 2 and 4 */
+  if (pInitArgs->flags & CKF_OS_LOCKING_OK) {
+    *pLocking_state = MultiThreaded;
+    return CKR_OK;
+  }
+  if ((CK_CREATEMUTEX) NULL != pInitArgs->CreateMutex) functionCount++;
+  if ((CK_DESTROYMUTEX) NULL != pInitArgs->DestroyMutex) functionCount++;
+  if ((CK_LOCKMUTEX) NULL != pInitArgs->LockMutex) functionCount++;
+  if ((CK_UNLOCKMUTEX) NULL != pInitArgs->UnlockMutex) functionCount++;
+
+  /* CKF_OS_LOCKING_OK is not set, and not functions supplied, 
+   * explicit case 1 */
+  if (0 == functionCount) {
+    *pLocking_state = SingleThreaded;
+    return CKR_OK;
+  }
+
+  /* OS_LOCKING_OK is not set and functions have been supplied. Since
+   * ckfw uses nssbase library which explicitly calls NSPR, and since 
+   * there is no way to reliably override these explicit calls to NSPR,
+   * therefore we can't support applications which have their own threading 
+   * module.  Return CKR_CANT_LOCK if they supplied the correct number of 
+   * arguments, or CKR_ARGUMENTS_BAD if they did not in either case we will 
+   * fail the initialize */
+  return (4 == functionCount) ? CKR_CANT_LOCK : CKR_ARGUMENTS_BAD;
+}
+
+static PRInt32 liveInstances;
+
+/*
+ * NSSCKFWC_Initialize
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Initialize
+(
+  NSSCKFWInstance **pFwInstance,
+  NSSCKMDInstance *mdInstance,
+  CK_VOID_PTR pInitArgs
+)
+{
+  CK_RV error = CKR_OK;
+  CryptokiLockingState locking_state;
+
+  if( (NSSCKFWInstance **)NULL == pFwInstance ) {
+    error = CKR_GENERAL_ERROR;
+    goto loser;
+  }
+
+  if (*pFwInstance) {
+    error = CKR_CRYPTOKI_ALREADY_INITIALIZED;
+    goto loser;
+  }
+
+  if (!mdInstance) {
+    error = CKR_GENERAL_ERROR;
+    goto loser;
+  }
+
+  error = nssCKFW_GetThreadSafeState(pInitArgs,&locking_state);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  *pFwInstance = nssCKFWInstance_Create(pInitArgs, locking_state, mdInstance, &error);
+  if (!*pFwInstance) {
+    goto loser;
+  }
+  PR_ATOMIC_INCREMENT(&liveInstances);
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CANT_LOCK:
+  case CKR_CRYPTOKI_ALREADY_INITIALIZED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_NEED_TO_CREATE_THREADS:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_Finalize
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Finalize
+(
+  NSSCKFWInstance **pFwInstance
+)
+{
+  CK_RV error = CKR_OK;
+
+  if( (NSSCKFWInstance **)NULL == pFwInstance ) {
+    error = CKR_GENERAL_ERROR;
+    goto loser;
+  }
+
+  if (!*pFwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  error = nssCKFWInstance_Destroy(*pFwInstance);
+
+  /* In any case */
+  *pFwInstance = (NSSCKFWInstance *)NULL;
+
+ loser:
+  switch( error ) {
+  PRInt32 remainingInstances;
+  case CKR_OK:
+    remainingInstances = PR_ATOMIC_DECREMENT(&liveInstances);
+    if (!remainingInstances) {
+	nssArena_Shutdown();
+    }
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+    break;
+  default:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  /*
+   * A thread's error stack is automatically destroyed when the thread
+   * terminates or, for the primordial thread, by PR_Cleanup.  On
+   * Windows with MinGW, the thread private data destructor PR_Free
+   * registered by this module is actually a thunk for PR_Free defined
+   * in this module.  When the thread that unloads this module terminates
+   * or calls PR_Cleanup, the thunk for PR_Free is already gone with the
+   * module.  Therefore we need to destroy the error stack before the
+   * module is unloaded.
+   */
+  nss_DestroyErrorStack();
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetInfo
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetInfo
+(
+  NSSCKFWInstance *fwInstance,
+  CK_INFO_PTR pInfo
+)
+{
+  CK_RV error = CKR_OK;
+
+  if( (CK_INFO_PTR)CK_NULL_PTR == pInfo ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here means a caller error
+   */
+  (void)nsslibc_memset(pInfo, 0, sizeof(CK_INFO));
+
+  pInfo->cryptokiVersion = nssCKFWInstance_GetCryptokiVersion(fwInstance);
+
+  error = nssCKFWInstance_GetManufacturerID(fwInstance, pInfo->manufacturerID);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  pInfo->flags = nssCKFWInstance_GetFlags(fwInstance);
+
+  error = nssCKFWInstance_GetLibraryDescription(fwInstance, pInfo->libraryDescription);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  pInfo->libraryVersion = nssCKFWInstance_GetLibraryVersion(fwInstance);
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+    break;
+  default:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+  
+/*
+ * C_GetFunctionList is implemented entirely in the Module's file which
+ * includes the Framework API insert file.  It requires no "actual"
+ * NSSCKFW routine.
+ */
+
+/*
+ * NSSCKFWC_GetSlotList
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetSlotList
+(
+  NSSCKFWInstance *fwInstance,
+  CK_BBOOL tokenPresent,
+  CK_SLOT_ID_PTR pSlotList,
+  CK_ULONG_PTR pulCount
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  switch( tokenPresent ) {
+  case CK_TRUE:
+  case CK_FALSE:
+    break;
+  default:
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  if( (CK_ULONG_PTR)CK_NULL_PTR == pulCount ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (CK_SLOT_ID_PTR)CK_NULL_PTR == pSlotList ) {
+    *pulCount = nSlots;
+    return CKR_OK;
+  } 
+    
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pSlotList, 0, *pulCount * sizeof(CK_SLOT_ID));
+
+  if( *pulCount < nSlots ) {
+    *pulCount = nSlots;
+    error = CKR_BUFFER_TOO_SMALL;
+    goto loser;
+  } else {
+    CK_ULONG i;
+    *pulCount = nSlots;
+    
+    /* 
+     * Our secret "mapping": CK_SLOT_IDs are integers [1,N], and we
+     * just index one when we need it.
+     */
+
+    for( i = 0; i < nSlots; i++ ) {
+      pSlotList[i] = i+1;
+    }
+
+    return CKR_OK;
+  }
+
+ loser:
+  switch( error ) {
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+ 
+/*
+ * NSSCKFWC_GetSlotInfo
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetSlotInfo
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID,
+  CK_SLOT_INFO_PTR pInfo
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  if( (CK_SLOT_INFO_PTR)CK_NULL_PTR == pInfo ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pInfo, 0, sizeof(CK_SLOT_INFO));
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  error = nssCKFWSlot_GetSlotDescription(fwSlot, pInfo->slotDescription);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  error = nssCKFWSlot_GetManufacturerID(fwSlot, pInfo->manufacturerID);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  if( nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    pInfo->flags |= CKF_TOKEN_PRESENT;
+  }
+
+  if( nssCKFWSlot_GetRemovableDevice(fwSlot) ) {
+    pInfo->flags |= CKF_REMOVABLE_DEVICE;
+  }
+
+  if( nssCKFWSlot_GetHardwareSlot(fwSlot) ) {
+    pInfo->flags |= CKF_HW_SLOT;
+  }
+
+  pInfo->hardwareVersion = nssCKFWSlot_GetHardwareVersion(fwSlot);
+  pInfo->firmwareVersion = nssCKFWSlot_GetFirmwareVersion(fwSlot);
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SLOT_ID_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetTokenInfo
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetTokenInfo
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID,
+  CK_TOKEN_INFO_PTR pInfo
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  if( (CK_TOKEN_INFO_PTR)CK_NULL_PTR == pInfo ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pInfo, 0, sizeof(CK_TOKEN_INFO));
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  error = nssCKFWToken_GetLabel(fwToken, pInfo->label);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  error = nssCKFWToken_GetManufacturerID(fwToken, pInfo->manufacturerID);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  error = nssCKFWToken_GetModel(fwToken, pInfo->model);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  error = nssCKFWToken_GetSerialNumber(fwToken, pInfo->serialNumber);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  if( nssCKFWToken_GetHasRNG(fwToken) ) {
+    pInfo->flags |= CKF_RNG;
+  }
+
+  if( nssCKFWToken_GetIsWriteProtected(fwToken) ) {
+    pInfo->flags |= CKF_WRITE_PROTECTED;
+  }
+
+  if( nssCKFWToken_GetLoginRequired(fwToken) ) {
+    pInfo->flags |= CKF_LOGIN_REQUIRED;
+  }
+
+  if( nssCKFWToken_GetUserPinInitialized(fwToken) ) {
+    pInfo->flags |= CKF_USER_PIN_INITIALIZED;
+  }
+
+  if( nssCKFWToken_GetRestoreKeyNotNeeded(fwToken) ) {
+    pInfo->flags |= CKF_RESTORE_KEY_NOT_NEEDED;
+  }
+
+  if( nssCKFWToken_GetHasClockOnToken(fwToken) ) {
+    pInfo->flags |= CKF_CLOCK_ON_TOKEN;
+  }
+
+  if( nssCKFWToken_GetHasProtectedAuthenticationPath(fwToken) ) {
+    pInfo->flags |= CKF_PROTECTED_AUTHENTICATION_PATH;
+  }
+
+  if( nssCKFWToken_GetSupportsDualCryptoOperations(fwToken) ) {
+    pInfo->flags |= CKF_DUAL_CRYPTO_OPERATIONS;
+  }
+
+  pInfo->ulMaxSessionCount = nssCKFWToken_GetMaxSessionCount(fwToken);
+  pInfo->ulSessionCount = nssCKFWToken_GetSessionCount(fwToken);
+  pInfo->ulMaxRwSessionCount = nssCKFWToken_GetMaxRwSessionCount(fwToken);
+  pInfo->ulRwSessionCount= nssCKFWToken_GetRwSessionCount(fwToken);
+  pInfo->ulMaxPinLen = nssCKFWToken_GetMaxPinLen(fwToken);
+  pInfo->ulMinPinLen = nssCKFWToken_GetMinPinLen(fwToken);
+  pInfo->ulTotalPublicMemory = nssCKFWToken_GetTotalPublicMemory(fwToken);
+  pInfo->ulFreePublicMemory = nssCKFWToken_GetFreePublicMemory(fwToken);
+  pInfo->ulTotalPrivateMemory = nssCKFWToken_GetTotalPrivateMemory(fwToken);
+  pInfo->ulFreePrivateMemory = nssCKFWToken_GetFreePrivateMemory(fwToken);
+  pInfo->hardwareVersion = nssCKFWToken_GetHardwareVersion(fwToken);
+  pInfo->firmwareVersion = nssCKFWToken_GetFirmwareVersion(fwToken);
+  
+  error = nssCKFWToken_GetUTCTime(fwToken, pInfo->utcTime);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_DEVICE_REMOVED:
+  case CKR_TOKEN_NOT_PRESENT:
+    if (fwToken)
+      nssCKFWToken_Destroy(fwToken);
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SLOT_ID_INVALID:
+  case CKR_TOKEN_NOT_RECOGNIZED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_WaitForSlotEvent
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_WaitForSlotEvent
+(
+  NSSCKFWInstance *fwInstance,
+  CK_FLAGS flags,
+  CK_SLOT_ID_PTR pSlot,
+  CK_VOID_PTR pReserved
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  CK_BBOOL block;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  CK_ULONG i;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  if( flags & ~CKF_DONT_BLOCK ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  block = (flags & CKF_DONT_BLOCK) ? CK_TRUE : CK_FALSE;
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (CK_SLOT_ID_PTR)CK_NULL_PTR == pSlot ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  if( (CK_VOID_PTR)CK_NULL_PTR != pReserved ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = nssCKFWInstance_WaitForSlotEvent(fwInstance, block, &error);
+  if (!fwSlot) {
+    goto loser;
+  }
+
+  for( i = 0; i < nSlots; i++ ) {
+    if( fwSlot == slots[i] ) {
+      *pSlot = (CK_SLOT_ID)(CK_ULONG)(i+1);
+      return CKR_OK;
+    }
+  }
+
+  error = CKR_GENERAL_ERROR; /* returned something not in the slot list */
+
+ loser:
+  switch( error ) {
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_NO_EVENT:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetMechanismList
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetMechanismList
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID,
+  CK_MECHANISM_TYPE_PTR pMechanismList,
+  CK_ULONG_PTR pulCount
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
+  CK_ULONG count;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  if( (CK_ULONG_PTR)CK_NULL_PTR == pulCount ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  count = nssCKFWToken_GetMechanismCount(fwToken);
+
+  if( (CK_MECHANISM_TYPE_PTR)CK_NULL_PTR == pMechanismList ) {
+    *pulCount = count;
+    return CKR_OK;
+  }
+
+  if( *pulCount < count ) {
+    *pulCount = count;
+    error = CKR_BUFFER_TOO_SMALL;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pMechanismList, 0, *pulCount * sizeof(CK_MECHANISM_TYPE));
+
+  *pulCount = count;
+
+  if( 0 != count ) {
+    error = nssCKFWToken_GetMechanismTypes(fwToken, pMechanismList);
+  } else {
+    error = CKR_OK;
+  }
+
+  if( CKR_OK == error ) {
+    return CKR_OK;
+  }
+
+ loser:
+  switch( error ) {
+  case CKR_DEVICE_REMOVED:
+  case CKR_TOKEN_NOT_PRESENT:
+    if (fwToken)
+      nssCKFWToken_Destroy(fwToken);
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SLOT_ID_INVALID:
+  case CKR_TOKEN_NOT_RECOGNIZED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetMechanismInfo
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetMechanismInfo
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID,
+  CK_MECHANISM_TYPE type,
+  CK_MECHANISM_INFO_PTR pInfo
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  if( (CK_MECHANISM_INFO_PTR)CK_NULL_PTR == pInfo ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pInfo, 0, sizeof(CK_MECHANISM_INFO));
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, type, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  pInfo->ulMinKeySize = nssCKFWMechanism_GetMinKeySize(fwMechanism, &error);
+  pInfo->ulMaxKeySize = nssCKFWMechanism_GetMaxKeySize(fwMechanism, &error);
+
+  if( nssCKFWMechanism_GetInHardware(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_HW;
+  }
+  if( nssCKFWMechanism_GetCanEncrypt(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_ENCRYPT;
+  }
+  if( nssCKFWMechanism_GetCanDecrypt(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_DECRYPT;
+  }
+  if( nssCKFWMechanism_GetCanDigest(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_DIGEST;
+  }
+  if( nssCKFWMechanism_GetCanSign(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_SIGN;
+  }
+  if( nssCKFWMechanism_GetCanSignRecover(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_SIGN_RECOVER;
+  }
+  if( nssCKFWMechanism_GetCanVerify(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_VERIFY;
+  }
+  if( nssCKFWMechanism_GetCanVerifyRecover(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_VERIFY_RECOVER;
+  }
+  if( nssCKFWMechanism_GetCanGenerate(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_GENERATE;
+  }
+  if( nssCKFWMechanism_GetCanGenerateKeyPair(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_GENERATE_KEY_PAIR;
+  }
+  if( nssCKFWMechanism_GetCanWrap(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_WRAP;
+  }
+  if( nssCKFWMechanism_GetCanUnwrap(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_UNWRAP;
+  }
+  if( nssCKFWMechanism_GetCanDerive(fwMechanism, &error) ) {
+    pInfo->flags |= CKF_DERIVE;
+  }
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  return error;
+
+ loser:
+  switch( error ) {
+  case CKR_DEVICE_REMOVED:
+  case CKR_TOKEN_NOT_PRESENT:
+    if (fwToken)
+      nssCKFWToken_Destroy(fwToken);
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_MECHANISM_INVALID:
+  case CKR_SLOT_ID_INVALID:
+  case CKR_TOKEN_NOT_RECOGNIZED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_InitToken
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_InitToken
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID,
+  CK_CHAR_PTR pPin,
+  CK_ULONG ulPinLen,
+  CK_CHAR_PTR pLabel
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
+  NSSItem pin;
+  NSSUTF8 *label;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  pin.size = (PRUint32)ulPinLen;
+  pin.data = (void *)pPin;
+  label = (NSSUTF8 *)pLabel; /* identity conversion */
+
+  error = nssCKFWToken_InitToken(fwToken, &pin, label);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_DEVICE_REMOVED:
+  case CKR_TOKEN_NOT_PRESENT:
+    if (fwToken)
+      nssCKFWToken_Destroy(fwToken);
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_PIN_INCORRECT:
+  case CKR_PIN_LOCKED:
+  case CKR_SESSION_EXISTS:
+  case CKR_SLOT_ID_INVALID:
+  case CKR_TOKEN_NOT_RECOGNIZED:
+  case CKR_TOKEN_WRITE_PROTECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_InitPIN
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_InitPIN
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_CHAR_PTR pPin,
+  CK_ULONG ulPinLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSItem pin, *arg;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_CHAR_PTR)CK_NULL_PTR == pPin ) {
+    arg = (NSSItem *)NULL;
+  } else {
+    arg = &pin;
+    pin.size = (PRUint32)ulPinLen;
+    pin.data = (void *)pPin;
+  }
+
+  error = nssCKFWSession_InitPIN(fwSession, arg);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_PIN_INVALID:
+  case CKR_PIN_LEN_RANGE:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_SetPIN
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SetPIN
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_CHAR_PTR pOldPin,
+  CK_ULONG ulOldLen,
+  CK_CHAR_PTR pNewPin,
+  CK_ULONG ulNewLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSItem oldPin, newPin, *oldArg, *newArg;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_CHAR_PTR)CK_NULL_PTR == pOldPin ) {
+    oldArg = (NSSItem *)NULL;
+  } else {
+    oldArg = &oldPin;
+    oldPin.size = (PRUint32)ulOldLen;
+    oldPin.data = (void *)pOldPin;
+  }
+
+  if( (CK_CHAR_PTR)CK_NULL_PTR == pNewPin ) {
+    newArg = (NSSItem *)NULL;
+  } else {
+    newArg = &newPin;
+    newPin.size = (PRUint32)ulNewLen;
+    newPin.data = (void *)pNewPin;
+  }
+
+  error = nssCKFWSession_SetPIN(fwSession, oldArg, newArg);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_PIN_INCORRECT:
+  case CKR_PIN_INVALID:
+  case CKR_PIN_LEN_RANGE:
+  case CKR_PIN_LOCKED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TOKEN_WRITE_PROTECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_OpenSession
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_OpenSession
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID,
+  CK_FLAGS flags,
+  CK_VOID_PTR pApplication,
+  CK_NOTIFY Notify,
+  CK_SESSION_HANDLE_PTR phSession
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
+  NSSCKFWSession *fwSession;
+  CK_BBOOL rw;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  if( flags & CKF_RW_SESSION ) {
+    rw = CK_TRUE;
+  } else {
+    rw = CK_FALSE;
+  }
+
+  if( flags & CKF_SERIAL_SESSION ) {
+    ;
+  } else {
+    error = CKR_SESSION_PARALLEL_NOT_SUPPORTED;
+    goto loser;
+  }
+
+  if( flags & ~(CKF_RW_SESSION|CKF_SERIAL_SESSION) ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  if( (CK_SESSION_HANDLE_PTR)CK_NULL_PTR == phSession ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  *phSession = (CK_SESSION_HANDLE)0;
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwSession = nssCKFWToken_OpenSession(fwToken, rw, pApplication,
+               Notify, &error);
+  if (!fwSession) {
+    goto loser;
+  }
+
+  *phSession = nssCKFWInstance_CreateSessionHandle(fwInstance,
+                 fwSession, &error);
+  if( (CK_SESSION_HANDLE)0 == *phSession ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SESSION_COUNT:
+  case CKR_SESSION_EXISTS:
+  case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
+  case CKR_SESSION_READ_WRITE_SO_EXISTS:
+  case CKR_SLOT_ID_INVALID:
+  case CKR_TOKEN_NOT_PRESENT:
+  case CKR_TOKEN_NOT_RECOGNIZED:
+  case CKR_TOKEN_WRITE_PROTECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_CloseSession
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_CloseSession
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  nssCKFWInstance_DestroySessionHandle(fwInstance, hSession);
+  error = nssCKFWSession_Destroy(fwSession, CK_TRUE);
+
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_CloseAllSessions
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_CloseAllSessions
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SLOT_ID slotID
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG nSlots;
+  NSSCKFWSlot **slots;
+  NSSCKFWSlot *fwSlot;
+  NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nSlots = nssCKFWInstance_GetNSlots(fwInstance, &error);
+  if( (CK_ULONG)0 == nSlots ) {
+    goto loser;
+  }
+
+  if( (slotID < 1) || (slotID > nSlots) ) {
+    error = CKR_SLOT_ID_INVALID;
+    goto loser;
+  }
+
+  slots = nssCKFWInstance_GetSlots(fwInstance, &error);
+  if( (NSSCKFWSlot **)NULL == slots ) {
+    goto loser;
+  }
+
+  fwSlot = slots[ slotID-1 ];
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  error = nssCKFWToken_CloseAllSessions(fwToken);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SLOT_ID_INVALID:
+  case CKR_TOKEN_NOT_PRESENT:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetSessionInfo
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetSessionInfo
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_SESSION_INFO_PTR pInfo
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWSlot *fwSlot;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_SESSION_INFO_PTR)CK_NULL_PTR == pInfo ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pInfo, 0, sizeof(CK_SESSION_INFO));
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR;
+    goto loser;
+  }
+
+  pInfo->slotID = nssCKFWSlot_GetSlotID(fwSlot);
+  pInfo->state = nssCKFWSession_GetSessionState(fwSession);
+
+  if( CK_TRUE == nssCKFWSession_IsRWSession(fwSession) ) {
+    pInfo->flags |= CKF_RW_SESSION;
+  }
+
+  pInfo->flags |= CKF_SERIAL_SESSION; /* Always true */
+
+  pInfo->ulDeviceError = nssCKFWSession_GetDeviceError(fwSession);
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetOperationState
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetOperationState
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pOperationState,
+  CK_ULONG_PTR pulOperationStateLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  CK_ULONG len;
+  NSSItem buf;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_ULONG_PTR)CK_NULL_PTR == pulOperationStateLen ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  len = nssCKFWSession_GetOperationStateLen(fwSession, &error);
+  if( ((CK_ULONG)0 == len) && (CKR_OK != error) ) {
+    goto loser;
+  }
+
+  if( (CK_BYTE_PTR)CK_NULL_PTR == pOperationState ) {
+    *pulOperationStateLen = len;
+    return CKR_OK;
+  }
+
+  if( *pulOperationStateLen < len ) {
+    *pulOperationStateLen = len;
+    error = CKR_BUFFER_TOO_SMALL;
+    goto loser;
+  }
+
+  buf.size = (PRUint32)*pulOperationStateLen;
+  buf.data = (void *)pOperationState;
+  *pulOperationStateLen = len;
+  error = nssCKFWSession_GetOperationState(fwSession, &buf);
+
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_STATE_UNSAVEABLE:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_SetOperationState
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SetOperationState
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pOperationState,
+  CK_ULONG ulOperationStateLen,
+  CK_OBJECT_HANDLE hEncryptionKey,
+  CK_OBJECT_HANDLE hAuthenticationKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *eKey;
+  NSSCKFWObject *aKey;
+  NSSItem state;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  if( (CK_BYTE_PTR)CK_NULL_PTR == pOperationState ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /* 
+   * We could loop through the buffer, to catch any purify errors
+   * in a place with a "user error" note.
+   */
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_OBJECT_HANDLE)0 == hEncryptionKey ) {
+    eKey = (NSSCKFWObject *)NULL;
+  } else {
+    eKey = nssCKFWInstance_ResolveObjectHandle(fwInstance, hEncryptionKey);
+    if (!eKey) {
+      error = CKR_KEY_HANDLE_INVALID;
+      goto loser;
+    }
+  }
+
+  if( (CK_OBJECT_HANDLE)0 == hAuthenticationKey ) {
+    aKey = (NSSCKFWObject *)NULL;
+  } else {
+    aKey = nssCKFWInstance_ResolveObjectHandle(fwInstance, hAuthenticationKey);
+    if (!aKey) {
+      error = CKR_KEY_HANDLE_INVALID;
+      goto loser;
+    }
+  }
+
+  state.data = pOperationState;
+  state.size = ulOperationStateLen;
+
+  error = nssCKFWSession_SetOperationState(fwSession, &state, eKey, aKey);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_CHANGED:
+  case CKR_KEY_NEEDED:
+  case CKR_KEY_NOT_NEEDED:
+  case CKR_SAVED_STATE_INVALID:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_Login
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Login
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_USER_TYPE userType,
+  CK_CHAR_PTR pPin,
+  CK_ULONG ulPinLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSItem pin, *arg;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_CHAR_PTR)CK_NULL_PTR == pPin ) {
+    arg = (NSSItem *)NULL;
+  } else {
+    arg = &pin;
+    pin.size = (PRUint32)ulPinLen;
+    pin.data = (void *)pPin;
+  }
+
+  error = nssCKFWSession_Login(fwSession, userType, arg);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_PIN_EXPIRED:
+  case CKR_PIN_INCORRECT:
+  case CKR_PIN_LOCKED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY_EXISTS:
+  case CKR_USER_ALREADY_LOGGED_IN:
+  case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
+  case CKR_USER_PIN_NOT_INITIALIZED:
+  case CKR_USER_TOO_MANY_TYPES:
+  case CKR_USER_TYPE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_Logout
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Logout
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Logout(fwSession);
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_CreateObject
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_CreateObject
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulCount,
+  CK_OBJECT_HANDLE_PTR phObject
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_OBJECT_HANDLE_PTR)CK_NULL_PTR == phObject ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  *phObject = (CK_OBJECT_HANDLE)0;
+
+  fwObject = nssCKFWSession_CreateObject(fwSession, pTemplate,
+               ulCount, &error);
+  if (!fwObject) {
+    goto loser;
+  }
+
+  *phObject = nssCKFWInstance_CreateObjectHandle(fwInstance, fwObject, &error);
+  if( (CK_OBJECT_HANDLE)0 == *phObject ) {
+    nssCKFWObject_Destroy(fwObject);
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCOMPLETE:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_CopyObject
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_CopyObject
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE hObject,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulCount,
+  CK_OBJECT_HANDLE_PTR phNewObject
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWObject *fwNewObject;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_OBJECT_HANDLE_PTR)CK_NULL_PTR == phNewObject ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  *phNewObject = (CK_OBJECT_HANDLE)0;
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hObject);
+  if (!fwObject) {
+    error = CKR_OBJECT_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwNewObject = nssCKFWSession_CopyObject(fwSession, fwObject,
+                  pTemplate, ulCount, &error);
+  if (!fwNewObject) {
+    goto loser;
+  }
+
+  *phNewObject = nssCKFWInstance_CreateObjectHandle(fwInstance, 
+                   fwNewObject, &error);
+  if( (CK_OBJECT_HANDLE)0 == *phNewObject ) {
+    nssCKFWObject_Destroy(fwNewObject);
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OBJECT_HANDLE_INVALID:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_DestroyObject
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DestroyObject
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE hObject
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hObject);
+  if (!fwObject) {
+    error = CKR_OBJECT_HANDLE_INVALID;
+    goto loser;
+  }
+
+  nssCKFWInstance_DestroyObjectHandle(fwInstance, hObject);
+  nssCKFWObject_Destroy(fwObject);
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OBJECT_HANDLE_INVALID:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TOKEN_WRITE_PROTECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetObjectSize
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetObjectSize
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE hObject,
+  CK_ULONG_PTR pulSize
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hObject);
+  if (!fwObject) {
+    error = CKR_OBJECT_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_ULONG_PTR)CK_NULL_PTR == pulSize ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  *pulSize = (CK_ULONG)0;
+
+  *pulSize = nssCKFWObject_GetObjectSize(fwObject, &error);
+  if( ((CK_ULONG)0 == *pulSize) && (CKR_OK != error) ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_INFORMATION_SENSITIVE:
+  case CKR_OBJECT_HANDLE_INVALID:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetAttributeValue
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetAttributeValue
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE hObject,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulCount
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  CK_BBOOL sensitive = CK_FALSE;
+  CK_BBOOL invalid = CK_FALSE;
+  CK_BBOOL tooSmall = CK_FALSE;
+  CK_ULONG i;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hObject);
+  if (!fwObject) {
+    error = CKR_OBJECT_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_ATTRIBUTE_PTR)CK_NULL_PTR == pTemplate ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  for( i = 0; i < ulCount; i++ ) {
+    CK_ULONG size = nssCKFWObject_GetAttributeSize(fwObject, 
+                      pTemplate[i].type, &error);
+    if( (CK_ULONG)0 == size ) {
+      switch( error ) {
+      case CKR_ATTRIBUTE_SENSITIVE:
+      case CKR_INFORMATION_SENSITIVE:
+        sensitive = CK_TRUE;
+        pTemplate[i].ulValueLen = (CK_ULONG)(-1);
+        continue;
+      case CKR_ATTRIBUTE_TYPE_INVALID:
+        invalid = CK_TRUE;
+        pTemplate[i].ulValueLen = (CK_ULONG)(-1);
+        continue;
+      case CKR_OK:
+        break;
+      default:
+        goto loser;
+      }
+    }
+
+    if( (CK_VOID_PTR)CK_NULL_PTR == pTemplate[i].pValue ) {
+      pTemplate[i].ulValueLen = size;
+    } else {
+      NSSItem it, *p;
+
+      if( pTemplate[i].ulValueLen < size ) {
+        tooSmall = CK_TRUE;
+        continue;
+      }
+
+      it.size = (PRUint32)pTemplate[i].ulValueLen;
+      it.data = (void *)pTemplate[i].pValue;
+      p = nssCKFWObject_GetAttribute(fwObject, pTemplate[i].type, &it, 
+            (NSSArena *)NULL, &error);
+      if (!p) {
+        switch( error ) {
+        case CKR_ATTRIBUTE_SENSITIVE:
+        case CKR_INFORMATION_SENSITIVE:
+          sensitive = CK_TRUE;
+          pTemplate[i].ulValueLen = (CK_ULONG)(-1);
+          continue;
+        case CKR_ATTRIBUTE_TYPE_INVALID:
+          invalid = CK_TRUE;
+          pTemplate[i].ulValueLen = (CK_ULONG)(-1);
+          continue;
+        default:
+          goto loser;
+        }
+      }
+
+      pTemplate[i].ulValueLen = size;
+    }
+  }
+
+  if( sensitive ) {
+    error = CKR_ATTRIBUTE_SENSITIVE;
+    goto loser;
+  } else if( invalid ) {
+    error = CKR_ATTRIBUTE_TYPE_INVALID;
+    goto loser;
+  } else if( tooSmall ) {
+    error = CKR_BUFFER_TOO_SMALL;
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ATTRIBUTE_SENSITIVE:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OBJECT_HANDLE_INVALID:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+  
+/*
+ * NSSCKFWC_SetAttributeValue
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SetAttributeValue
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE hObject,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulCount
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  CK_ULONG i;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hObject);
+  if (!fwObject) {
+    error = CKR_OBJECT_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_ATTRIBUTE_PTR)CK_NULL_PTR == pTemplate ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  for (i=0; i < ulCount; i++) {
+    NSSItem value;
+
+    value.data = pTemplate[i].pValue;
+    value.size = pTemplate[i].ulValueLen;
+
+    error = nssCKFWObject_SetAttribute(fwObject, fwSession, 
+                                       pTemplate[i].type, &value);
+
+    if( CKR_OK != error ) {
+      goto loser;
+    }
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OBJECT_HANDLE_INVALID:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_FindObjectsInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_FindObjectsInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulCount
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWFindObjects *fwFindObjects;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( ((CK_ATTRIBUTE_PTR)CK_NULL_PTR == pTemplate) && (ulCount != 0) ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  fwFindObjects = nssCKFWSession_GetFWFindObjects(fwSession, &error);
+  if (fwFindObjects) {
+    error = CKR_OPERATION_ACTIVE;
+    goto loser;
+  }
+
+  if( CKR_OPERATION_NOT_INITIALIZED != error ) {
+    goto loser;
+  }
+
+  fwFindObjects = nssCKFWSession_FindObjectsInit(fwSession,
+                    pTemplate, ulCount, &error);
+  if (!fwFindObjects) {
+    goto loser;
+  }
+
+  error = nssCKFWSession_SetFWFindObjects(fwSession, fwFindObjects);
+
+  if( CKR_OK != error ) {
+    nssCKFWFindObjects_Destroy(fwFindObjects);
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_FindObjects
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_FindObjects
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE_PTR phObject,
+  CK_ULONG ulMaxObjectCount,
+  CK_ULONG_PTR pulObjectCount
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWFindObjects *fwFindObjects;
+  CK_ULONG i;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_OBJECT_HANDLE_PTR)CK_NULL_PTR == phObject ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(phObject, 0, sizeof(CK_OBJECT_HANDLE) * ulMaxObjectCount);
+  *pulObjectCount = (CK_ULONG)0;
+
+  fwFindObjects = nssCKFWSession_GetFWFindObjects(fwSession, &error);
+  if (!fwFindObjects) {
+    goto loser;
+  }
+
+  for( i = 0; i < ulMaxObjectCount; i++ ) {
+    NSSCKFWObject *fwObject = nssCKFWFindObjects_Next(fwFindObjects,
+                                NULL, &error);
+    if (!fwObject) {
+      break;
+    }
+
+    phObject[i] = nssCKFWInstance_FindObjectHandle(fwInstance, fwObject);
+    if( (CK_OBJECT_HANDLE)0 == phObject[i] ) {
+      phObject[i] = nssCKFWInstance_CreateObjectHandle(fwInstance, fwObject, &error);
+    }
+    if( (CK_OBJECT_HANDLE)0 == phObject[i] ) {
+      /* This isn't right either, is it? */
+      nssCKFWObject_Destroy(fwObject);
+      goto loser;
+    }
+  }
+
+  *pulObjectCount = i;
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_FindObjectsFinal
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_FindObjectsFinal
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWFindObjects *fwFindObjects;
+  
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwFindObjects = nssCKFWSession_GetFWFindObjects(fwSession, &error);
+  if (!fwFindObjects) {
+    error = CKR_OPERATION_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  nssCKFWFindObjects_Destroy(fwFindObjects);
+  error = nssCKFWSession_SetFWFindObjects(fwSession, 
+                                          (NSSCKFWFindObjects *)NULL);
+
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_EncryptInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_EncryptInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_EncryptInit(fwMechanism, pMechanism,
+                                        fwSession, fwObject);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_FUNCTION_NOT_PERMITTED:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_Encrypt
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Encrypt
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen,
+  CK_BYTE_PTR pEncryptedData,
+  CK_ULONG_PTR pulEncryptedDataLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_Encrypt, 
+           NSSCKFWCryptoOperationState_EncryptDecrypt,
+           pData, ulDataLen, pEncryptedData, pulEncryptedDataLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_INVALID:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_CLOSED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_EncryptUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_EncryptUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pPart,
+  CK_ULONG ulPartLen,
+  CK_BYTE_PTR pEncryptedPart,
+  CK_ULONG_PTR pulEncryptedPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Update(fwSession,
+           NSSCKFWCryptoOperationType_Encrypt, 
+           NSSCKFWCryptoOperationState_EncryptDecrypt,
+           pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_EncryptFinal
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_EncryptFinal
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pLastEncryptedPart,
+  CK_ULONG_PTR pulLastEncryptedPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Final(fwSession,
+           NSSCKFWCryptoOperationType_Encrypt, 
+           NSSCKFWCryptoOperationState_EncryptDecrypt,
+           pLastEncryptedPart, pulLastEncryptedPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DecryptInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DecryptInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_DecryptInit(fwMechanism, pMechanism, 
+                                       fwSession, fwObject);
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_FUNCTION_NOT_PERMITTED:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_Decrypt
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Decrypt
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pEncryptedData,
+  CK_ULONG ulEncryptedDataLen,
+  CK_BYTE_PTR pData,
+  CK_ULONG_PTR pulDataLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_Decrypt, 
+           NSSCKFWCryptoOperationState_EncryptDecrypt,
+           pEncryptedData, ulEncryptedDataLen, pData, pulDataLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_ENCRYPTED_DATA_INVALID:
+  case CKR_ENCRYPTED_DATA_LEN_RANGE:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  case CKR_DATA_LEN_RANGE:
+    error = CKR_ENCRYPTED_DATA_LEN_RANGE;
+    break;
+  case CKR_DATA_INVALID:
+    error = CKR_ENCRYPTED_DATA_INVALID;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DecryptUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DecryptUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pEncryptedPart,
+  CK_ULONG ulEncryptedPartLen,
+  CK_BYTE_PTR pPart,
+  CK_ULONG_PTR pulPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Update(fwSession,
+           NSSCKFWCryptoOperationType_Decrypt, 
+           NSSCKFWCryptoOperationState_EncryptDecrypt,
+           pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_ENCRYPTED_DATA_INVALID:
+  case CKR_ENCRYPTED_DATA_LEN_RANGE:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  case CKR_DATA_LEN_RANGE:
+    error = CKR_ENCRYPTED_DATA_LEN_RANGE;
+    break;
+  case CKR_DATA_INVALID:
+    error = CKR_ENCRYPTED_DATA_INVALID;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DecryptFinal
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DecryptFinal
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pLastPart,
+  CK_ULONG_PTR pulLastPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Final(fwSession,
+           NSSCKFWCryptoOperationType_Decrypt, 
+           NSSCKFWCryptoOperationState_EncryptDecrypt,
+           pLastPart, pulLastPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_ENCRYPTED_DATA_INVALID:
+  case CKR_ENCRYPTED_DATA_LEN_RANGE:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  case CKR_DATA_LEN_RANGE:
+    error = CKR_ENCRYPTED_DATA_LEN_RANGE;
+    break;
+  case CKR_DATA_INVALID:
+    error = CKR_ENCRYPTED_DATA_INVALID;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DigestInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DigestInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_DigestInit(fwMechanism, pMechanism, fwSession);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_Digest
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Digest
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen,
+  CK_BYTE_PTR pDigest,
+  CK_ULONG_PTR pulDigestLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_Digest, 
+           NSSCKFWCryptoOperationState_Digest,
+           pData, ulDataLen, pDigest, pulDigestLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DigestUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DigestUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_DigestUpdate(fwSession,
+           NSSCKFWCryptoOperationType_Digest, 
+           NSSCKFWCryptoOperationState_Digest,
+           pData, ulDataLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DigestKey
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DigestKey
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_DigestKey(fwSession, fwObject);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_INDIGESTIBLE:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DigestFinal
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DigestFinal
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pDigest,
+  CK_ULONG_PTR pulDigestLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Final(fwSession,
+           NSSCKFWCryptoOperationType_Digest, 
+           NSSCKFWCryptoOperationState_Digest,
+           pDigest, pulDigestLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SignInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SignInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_SignInit(fwMechanism, pMechanism, fwSession, 
+                                    fwObject);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_FUNCTION_NOT_PERMITTED:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_Sign
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Sign
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen,
+  CK_BYTE_PTR pSignature,
+  CK_ULONG_PTR pulSignatureLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_Sign, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pData, ulDataLen, pSignature, pulSignatureLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_INVALID:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+  case CKR_FUNCTION_REJECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SignUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SignUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pPart,
+  CK_ULONG ulPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_DigestUpdate(fwSession,
+           NSSCKFWCryptoOperationType_Sign, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pPart, ulPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SignFinal
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SignFinal
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pSignature,
+  CK_ULONG_PTR pulSignatureLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Final(fwSession,
+           NSSCKFWCryptoOperationType_Sign, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pSignature, pulSignatureLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+  case CKR_FUNCTION_REJECTED:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SignRecoverInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SignRecoverInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_SignRecoverInit(fwMechanism, pMechanism, fwSession, 
+                                           fwObject);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_FUNCTION_NOT_PERMITTED:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SignRecover
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SignRecover
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen,
+  CK_BYTE_PTR pSignature,
+  CK_ULONG_PTR pulSignatureLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_SignRecover, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pData, ulDataLen, pSignature, pulSignatureLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_INVALID:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_VerifyInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_VerifyInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_VerifyInit(fwMechanism, pMechanism, fwSession,
+                                      fwObject);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_FUNCTION_NOT_PERMITTED:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_Verify
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_Verify
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pData,
+  CK_ULONG ulDataLen,
+  CK_BYTE_PTR pSignature,
+  CK_ULONG ulSignatureLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_Verify, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pData, ulDataLen, pSignature, &ulSignatureLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_INVALID:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SIGNATURE_INVALID:
+  case CKR_SIGNATURE_LEN_RANGE:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_VerifyUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_VerifyUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pPart,
+  CK_ULONG ulPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_DigestUpdate(fwSession,
+           NSSCKFWCryptoOperationType_Verify, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pPart, ulPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_VerifyFinal
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_VerifyFinal
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pSignature,
+  CK_ULONG ulSignatureLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_Final(fwSession,
+           NSSCKFWCryptoOperationType_Verify, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pSignature, &ulSignatureLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SIGNATURE_INVALID:
+  case CKR_SIGNATURE_LEN_RANGE:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_VerifyRecoverInit
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_VerifyRecoverInit
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error = nssCKFWMechanism_VerifyRecoverInit(fwMechanism, pMechanism, 
+                                             fwSession, fwObject);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_FUNCTION_NOT_PERMITTED:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_CLOSED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_VerifyRecover
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_VerifyRecover
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pSignature,
+  CK_ULONG ulSignatureLen,
+  CK_BYTE_PTR pData,
+  CK_ULONG_PTR pulDataLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateFinal(fwSession,
+           NSSCKFWCryptoOperationType_VerifyRecover, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pSignature, ulSignatureLen, pData, pulDataLen);
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_INVALID:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SIGNATURE_INVALID:
+  case CKR_SIGNATURE_LEN_RANGE:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DigestEncryptUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DigestEncryptUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pPart,
+  CK_ULONG ulPartLen,
+  CK_BYTE_PTR pEncryptedPart,
+  CK_ULONG_PTR pulEncryptedPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateCombo(fwSession,
+           NSSCKFWCryptoOperationType_Encrypt, 
+           NSSCKFWCryptoOperationType_Digest, 
+           NSSCKFWCryptoOperationState_Digest,
+           pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DecryptDigestUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DecryptDigestUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pEncryptedPart,
+  CK_ULONG ulEncryptedPartLen,
+  CK_BYTE_PTR pPart,
+  CK_ULONG_PTR pulPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateCombo(fwSession,
+           NSSCKFWCryptoOperationType_Decrypt, 
+           NSSCKFWCryptoOperationType_Digest, 
+           NSSCKFWCryptoOperationState_Digest,
+           pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_ENCRYPTED_DATA_INVALID:
+  case CKR_ENCRYPTED_DATA_LEN_RANGE:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  case CKR_DATA_INVALID:
+    error = CKR_ENCRYPTED_DATA_INVALID;
+    break;
+  case CKR_DATA_LEN_RANGE:
+    error = CKR_ENCRYPTED_DATA_LEN_RANGE;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SignEncryptUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SignEncryptUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pPart,
+  CK_ULONG ulPartLen,
+  CK_BYTE_PTR pEncryptedPart,
+  CK_ULONG_PTR pulEncryptedPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateCombo(fwSession,
+           NSSCKFWCryptoOperationType_Encrypt, 
+           NSSCKFWCryptoOperationType_Sign, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DecryptVerifyUpdate
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DecryptVerifyUpdate
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pEncryptedPart,
+  CK_ULONG ulEncryptedPartLen,
+  CK_BYTE_PTR pPart,
+  CK_ULONG_PTR pulPartLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  error = nssCKFWSession_UpdateCombo(fwSession,
+           NSSCKFWCryptoOperationType_Decrypt, 
+           NSSCKFWCryptoOperationType_Verify, 
+           NSSCKFWCryptoOperationState_SignVerify,
+           pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DATA_LEN_RANGE:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_ENCRYPTED_DATA_INVALID:
+  case CKR_ENCRYPTED_DATA_LEN_RANGE:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_NOT_INITIALIZED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+    break;
+  case CKR_DATA_INVALID:
+    error = CKR_ENCRYPTED_DATA_INVALID;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_GenerateKey
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GenerateKey
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulCount,
+  CK_OBJECT_HANDLE_PTR phKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  fwObject = nssCKFWMechanism_GenerateKey(
+                fwMechanism, 
+                pMechanism, 
+                fwSession, 
+                pTemplate, 
+                ulCount, 
+                &error);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+  if (!fwObject) {
+    goto loser;
+  }
+  *phKey= nssCKFWInstance_CreateObjectHandle(fwInstance, fwObject, &error);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCOMPLETE:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_GenerateKeyPair
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GenerateKeyPair
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+  CK_ULONG ulPublicKeyAttributeCount,
+  CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+  CK_ULONG ulPrivateKeyAttributeCount,
+  CK_OBJECT_HANDLE_PTR phPublicKey,
+  CK_OBJECT_HANDLE_PTR phPrivateKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwPrivateKeyObject;
+  NSSCKFWObject *fwPublicKeyObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  error= nssCKFWMechanism_GenerateKeyPair(
+                fwMechanism, 
+                pMechanism, 
+                fwSession, 
+                pPublicKeyTemplate, 
+                ulPublicKeyAttributeCount, 
+                pPublicKeyTemplate, 
+                ulPublicKeyAttributeCount, 
+                &fwPublicKeyObject,
+                &fwPrivateKeyObject);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+  if (CKR_OK != error) {
+    goto loser;
+  }
+  *phPublicKey = nssCKFWInstance_CreateObjectHandle(fwInstance, 
+                                                 fwPublicKeyObject, 
+                                                 &error);
+  if (CKR_OK != error) {
+    goto loser;
+  }
+  *phPrivateKey = nssCKFWInstance_CreateObjectHandle(fwInstance, 
+                                                 fwPrivateKeyObject, 
+                                                 &error);
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_DOMAIN_PARAMS_INVALID:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCOMPLETE:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_WrapKey
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_WrapKey
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hWrappingKey,
+  CK_OBJECT_HANDLE hKey,
+  CK_BYTE_PTR pWrappedKey,
+  CK_ULONG_PTR pulWrappedKeyLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwKeyObject;
+  NSSCKFWObject *fwWrappingKeyObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+  NSSItem  wrappedKey;
+  CK_ULONG wrappedKeyLength = 0;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwWrappingKeyObject = nssCKFWInstance_ResolveObjectHandle(fwInstance,
+                                                            hWrappingKey);
+  if (!fwWrappingKeyObject) {
+    error = CKR_WRAPPING_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwKeyObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hKey);
+  if (!fwKeyObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  /*
+   * first get the length...
+   */
+  wrappedKeyLength = nssCKFWMechanism_GetWrapKeyLength(
+                fwMechanism, 
+                pMechanism, 
+                fwSession, 
+                fwWrappingKeyObject,
+                fwKeyObject,
+                &error);
+  if ((CK_ULONG) 0 == wrappedKeyLength) {
+    nssCKFWMechanism_Destroy(fwMechanism);
+    goto loser;
+  }
+  if ((CK_BYTE_PTR)NULL == pWrappedKey) {
+    *pulWrappedKeyLen = wrappedKeyLength;
+    nssCKFWMechanism_Destroy(fwMechanism);
+    return CKR_OK;
+  }
+  if (wrappedKeyLength > *pulWrappedKeyLen) {
+    *pulWrappedKeyLen = wrappedKeyLength;
+    nssCKFWMechanism_Destroy(fwMechanism);
+    error = CKR_BUFFER_TOO_SMALL;
+    goto loser;
+  }
+    
+
+  wrappedKey.data = pWrappedKey;
+  wrappedKey.size = wrappedKeyLength;
+
+  error = nssCKFWMechanism_WrapKey(
+                fwMechanism, 
+                pMechanism, 
+                fwSession, 
+                fwWrappingKeyObject,
+                fwKeyObject,
+                &wrappedKey);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+  *pulWrappedKeyLen = wrappedKey.size;
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_NOT_WRAPPABLE:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_UNEXTRACTABLE:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_WRAPPING_KEY_HANDLE_INVALID:
+  case CKR_WRAPPING_KEY_SIZE_RANGE:
+  case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
+    break;
+  case CKR_KEY_TYPE_INCONSISTENT:
+    error = CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_UnwrapKey
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_UnwrapKey
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hUnwrappingKey,
+  CK_BYTE_PTR pWrappedKey,
+  CK_ULONG ulWrappedKeyLen,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulAttributeCount,
+  CK_OBJECT_HANDLE_PTR phKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWObject *fwWrappingKeyObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+  NSSItem  wrappedKey;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwWrappingKeyObject = nssCKFWInstance_ResolveObjectHandle(fwInstance,
+                                                            hUnwrappingKey);
+  if (!fwWrappingKeyObject) {
+    error = CKR_WRAPPING_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  wrappedKey.data = pWrappedKey;
+  wrappedKey.size = ulWrappedKeyLen;
+
+  fwObject = nssCKFWMechanism_UnwrapKey(
+                fwMechanism, 
+                pMechanism, 
+                fwSession, 
+                fwWrappingKeyObject,
+                &wrappedKey,
+                pTemplate, 
+                ulAttributeCount, 
+                &error);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+  if (!fwObject) {
+    goto loser;
+  }
+  *phKey = nssCKFWInstance_CreateObjectHandle(fwInstance, fwObject, &error);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_BUFFER_TOO_SMALL:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_DOMAIN_PARAMS_INVALID:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCOMPLETE:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
+  case CKR_UNWRAPPING_KEY_SIZE_RANGE:
+  case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
+  case CKR_USER_NOT_LOGGED_IN:
+  case CKR_WRAPPED_KEY_INVALID:
+  case CKR_WRAPPED_KEY_LEN_RANGE:
+    break;
+  case CKR_KEY_HANDLE_INVALID:
+    error = CKR_UNWRAPPING_KEY_HANDLE_INVALID;
+    break;
+  case CKR_KEY_SIZE_RANGE:
+    error = CKR_UNWRAPPING_KEY_SIZE_RANGE;
+    break;
+  case CKR_KEY_TYPE_INCONSISTENT:
+    error = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
+    break;
+  case CKR_ENCRYPTED_DATA_INVALID:
+    error = CKR_WRAPPED_KEY_INVALID;
+    break;
+  case CKR_ENCRYPTED_DATA_LEN_RANGE:
+    error = CKR_WRAPPED_KEY_LEN_RANGE;
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_DeriveKey
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_DeriveKey
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_MECHANISM_PTR pMechanism,
+  CK_OBJECT_HANDLE hBaseKey,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulAttributeCount,
+  CK_OBJECT_HANDLE_PTR phKey
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSCKFWObject *fwObject;
+  NSSCKFWObject *fwBaseKeyObject;
+  NSSCKFWSlot  *fwSlot;
+  NSSCKFWToken  *fwToken;
+  NSSCKFWMechanism *fwMechanism;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+  
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwBaseKeyObject = nssCKFWInstance_ResolveObjectHandle(fwInstance, hBaseKey);
+  if (!fwBaseKeyObject) {
+    error = CKR_KEY_HANDLE_INVALID;
+    goto loser;
+  }
+
+  fwSlot = nssCKFWSession_GetFWSlot(fwSession);
+  if (!fwSlot) {
+    error = CKR_GENERAL_ERROR; /* should never happen! */
+    goto loser;
+  }
+
+  if( CK_TRUE != nssCKFWSlot_GetTokenPresent(fwSlot) ) {
+    error = CKR_TOKEN_NOT_PRESENT;
+    goto loser;
+  }
+
+  fwToken = nssCKFWSlot_GetToken(fwSlot, &error);
+  if (!fwToken) {
+    goto loser;
+  }
+
+  fwMechanism = nssCKFWToken_GetMechanism(fwToken, pMechanism->mechanism, &error);
+  if (!fwMechanism) {
+    goto loser;
+  }
+
+  fwObject = nssCKFWMechanism_DeriveKey(
+                fwMechanism, 
+                pMechanism, 
+                fwSession, 
+                fwBaseKeyObject,
+                pTemplate, 
+                ulAttributeCount, 
+                &error);
+
+  nssCKFWMechanism_Destroy(fwMechanism);
+  if (!fwObject) {
+    goto loser;
+  }
+  *phKey = nssCKFWInstance_CreateObjectHandle(fwInstance, fwObject, &error);
+
+  if (CKR_OK == error) {
+    return CKR_OK;
+  }
+
+loser:
+  /* verify error */
+  switch( error ) {
+  case CKR_ARGUMENTS_BAD:
+  case CKR_ATTRIBUTE_READ_ONLY:
+  case CKR_ATTRIBUTE_TYPE_INVALID:
+  case CKR_ATTRIBUTE_VALUE_INVALID:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_DEVICE_REMOVED:
+  case CKR_DOMAIN_PARAMS_INVALID:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_KEY_HANDLE_INVALID:
+  case CKR_KEY_SIZE_RANGE:
+  case CKR_KEY_TYPE_INCONSISTENT:
+  case CKR_MECHANISM_INVALID:
+  case CKR_MECHANISM_PARAM_INVALID:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_PIN_EXPIRED:
+  case CKR_SESSION_CLOSED:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_SESSION_READ_ONLY:
+  case CKR_TEMPLATE_INCOMPLETE:
+  case CKR_TEMPLATE_INCONSISTENT:
+  case CKR_TOKEN_WRITE_PROTECTED:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+  return error;
+}
+
+/*
+ * NSSCKFWC_SeedRandom
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_SeedRandom
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pSeed,
+  CK_ULONG ulSeedLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSItem seed;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_BYTE_PTR)CK_NULL_PTR == pSeed ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /* We could read through the buffer in a Purify trap */
+
+  seed.size = (PRUint32)ulSeedLen;
+  seed.data = (void *)pSeed;
+
+  error = nssCKFWSession_SeedRandom(fwSession, &seed);
+
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_RANDOM_SEED_NOT_SUPPORTED:
+  case CKR_RANDOM_NO_RNG:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GenerateRandom
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GenerateRandom
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession,
+  CK_BYTE_PTR pRandomData,
+  CK_ULONG ulRandomLen
+)
+{
+  CK_RV error = CKR_OK;
+  NSSCKFWSession *fwSession;
+  NSSItem buffer;
+
+  if (!fwInstance) {
+    error = CKR_CRYPTOKI_NOT_INITIALIZED;
+    goto loser;
+  }
+
+  fwSession = nssCKFWInstance_ResolveSessionHandle(fwInstance, hSession);
+  if (!fwSession) {
+    error = CKR_SESSION_HANDLE_INVALID;
+    goto loser;
+  }
+
+  if( (CK_BYTE_PTR)CK_NULL_PTR == pRandomData ) {
+    error = CKR_ARGUMENTS_BAD;
+    goto loser;
+  }
+
+  /*
+   * A purify error here indicates caller error.
+   */
+  (void)nsslibc_memset(pRandomData, 0, ulRandomLen);
+
+  buffer.size = (PRUint32)ulRandomLen;
+  buffer.data = (void *)pRandomData;
+
+  error = nssCKFWSession_GetRandom(fwSession, &buffer);
+
+  if( CKR_OK != error ) {
+    goto loser;
+  }
+
+  return CKR_OK;
+
+ loser:
+  switch( error ) {
+  case CKR_SESSION_CLOSED:
+    /* destroy session? */
+    break;
+  case CKR_DEVICE_REMOVED:
+    /* (void)nssCKFWToken_Destroy(fwToken); */
+    break;
+  case CKR_ARGUMENTS_BAD:
+  case CKR_CRYPTOKI_NOT_INITIALIZED:
+  case CKR_DEVICE_ERROR:
+  case CKR_DEVICE_MEMORY:
+  case CKR_FUNCTION_CANCELED:
+  case CKR_FUNCTION_FAILED:
+  case CKR_GENERAL_ERROR:
+  case CKR_HOST_MEMORY:
+  case CKR_OPERATION_ACTIVE:
+  case CKR_RANDOM_NO_RNG:
+  case CKR_SESSION_HANDLE_INVALID:
+  case CKR_USER_NOT_LOGGED_IN:
+    break;
+  default:
+  case CKR_OK:
+    error = CKR_GENERAL_ERROR;
+    break;
+  }
+
+  return error;
+}
+
+/*
+ * NSSCKFWC_GetFunctionStatus
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_GetFunctionStatus
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession
+)
+{
+  return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+/*
+ * NSSCKFWC_CancelFunction
+ *
+ */
+NSS_IMPLEMENT CK_RV
+NSSCKFWC_CancelFunction
+(
+  NSSCKFWInstance *fwInstance,
+  CK_SESSION_HANDLE hSession
+)
+{
+  return CKR_FUNCTION_NOT_PARALLEL;
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)