diff nss/lib/ckfw/session.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/session.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,2460 @@
+/* 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/. */
+
+/*
+ * session.c
+ *
+ * This file implements the NSSCKFWSession type and methods.
+ */
+
+#ifndef CK_T
+#include "ck.h"
+#endif /* CK_T */
+
+/*
+ * NSSCKFWSession
+ *
+ *  -- create/destroy --
+ *  nssCKFWSession_Create
+ *  nssCKFWSession_Destroy
+ *
+ *  -- public accessors --
+ *  NSSCKFWSession_GetMDSession
+ *  NSSCKFWSession_GetArena
+ *  NSSCKFWSession_CallNotification
+ *  NSSCKFWSession_IsRWSession
+ *  NSSCKFWSession_IsSO
+ *
+ *  -- implement public accessors --
+ *  nssCKFWSession_GetMDSession
+ *  nssCKFWSession_GetArena
+ *  nssCKFWSession_CallNotification
+ *  nssCKFWSession_IsRWSession
+ *  nssCKFWSession_IsSO
+ *
+ *  -- private accessors --
+ *  nssCKFWSession_GetSlot
+ *  nssCKFWSession_GetSessionState
+ *  nssCKFWSession_SetFWFindObjects
+ *  nssCKFWSession_GetFWFindObjects
+ *  nssCKFWSession_SetMDSession
+ *  nssCKFWSession_SetHandle
+ *  nssCKFWSession_GetHandle
+ *  nssCKFWSession_RegisterSessionObject
+ *  nssCKFWSession_DeegisterSessionObject
+ *
+ *  -- module fronts --
+ *  nssCKFWSession_GetDeviceError
+ *  nssCKFWSession_Login
+ *  nssCKFWSession_Logout
+ *  nssCKFWSession_InitPIN
+ *  nssCKFWSession_SetPIN
+ *  nssCKFWSession_GetOperationStateLen
+ *  nssCKFWSession_GetOperationState
+ *  nssCKFWSession_SetOperationState
+ *  nssCKFWSession_CreateObject
+ *  nssCKFWSession_CopyObject
+ *  nssCKFWSession_FindObjectsInit
+ *  nssCKFWSession_SeedRandom
+ *  nssCKFWSession_GetRandom
+ */
+
+struct NSSCKFWSessionStr {
+  NSSArena *arena;
+  NSSCKMDSession *mdSession;
+  NSSCKFWToken *fwToken;
+  NSSCKMDToken *mdToken;
+  NSSCKFWInstance *fwInstance;
+  NSSCKMDInstance *mdInstance;
+  CK_VOID_PTR pApplication;
+  CK_NOTIFY Notify;
+
+  /*
+   * Everything above is set at creation time, and then not modified.
+   * The items below are atomic.  No locking required.  If we fear
+   * about pointer-copies being nonatomic, we'll lock fwFindObjects.
+   */
+
+  CK_BBOOL rw;
+  NSSCKFWFindObjects *fwFindObjects;
+  NSSCKFWCryptoOperation *fwOperationArray[NSSCKFWCryptoOperationState_Max];
+  nssCKFWHash *sessionObjectHash;
+  CK_SESSION_HANDLE hSession;
+};
+
+#ifdef DEBUG
+/*
+ * But first, the pointer-tracking stuff.
+ *
+ * NOTE: the pointer-tracking support in NSS/base currently relies
+ * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
+ * locking, which is tied into the runtime.  We need a pointer-tracker
+ * implementation that uses the locks supplied through C_Initialize.
+ * That support, however, can be filled in later.  So for now, I'll
+ * just do this routines as no-ops.
+ */
+
+static CK_RV
+session_add_pointer
+(
+  const NSSCKFWSession *fwSession
+)
+{
+  return CKR_OK;
+}
+
+static CK_RV
+session_remove_pointer
+(
+  const NSSCKFWSession *fwSession
+)
+{
+  return CKR_OK;
+}
+
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_verifyPointer
+(
+  const NSSCKFWSession *fwSession
+)
+{
+  return CKR_OK;
+}
+
+#endif /* DEBUG */
+
+/*
+ * nssCKFWSession_Create
+ *
+ */
+NSS_IMPLEMENT NSSCKFWSession *
+nssCKFWSession_Create
+(
+  NSSCKFWToken *fwToken,
+  CK_BBOOL rw,
+  CK_VOID_PTR pApplication,
+  CK_NOTIFY Notify,
+  CK_RV *pError
+)
+{
+  NSSArena *arena = (NSSArena *)NULL;
+  NSSCKFWSession *fwSession;
+  NSSCKFWSlot *fwSlot;
+
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (NSSCKFWSession *)NULL;
+  }
+
+  *pError = nssCKFWToken_verifyPointer(fwToken);
+  if( CKR_OK != *pError ) {
+    return (NSSCKFWSession *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  arena = NSSArena_Create();
+  if (!arena) {
+    *pError = CKR_HOST_MEMORY;
+    return (NSSCKFWSession *)NULL;
+  }
+
+  fwSession = nss_ZNEW(arena, NSSCKFWSession);
+  if (!fwSession) {
+    *pError = CKR_HOST_MEMORY;
+    goto loser;
+  }
+
+  fwSession->arena = arena;
+  fwSession->mdSession = (NSSCKMDSession *)NULL; /* set later */
+  fwSession->fwToken = fwToken;
+  fwSession->mdToken = nssCKFWToken_GetMDToken(fwToken);
+
+  fwSlot = nssCKFWToken_GetFWSlot(fwToken);
+  fwSession->fwInstance = nssCKFWSlot_GetFWInstance(fwSlot);
+  fwSession->mdInstance = nssCKFWSlot_GetMDInstance(fwSlot);
+
+  fwSession->rw = rw;
+  fwSession->pApplication = pApplication;
+  fwSession->Notify = Notify;
+
+  fwSession->fwFindObjects = (NSSCKFWFindObjects *)NULL;
+
+  fwSession->sessionObjectHash = nssCKFWHash_Create(fwSession->fwInstance, arena, pError);
+  if (!fwSession->sessionObjectHash) {
+    if( CKR_OK == *pError ) {
+      *pError = CKR_GENERAL_ERROR;
+    }
+    goto loser;
+  }
+
+#ifdef DEBUG
+  *pError = session_add_pointer(fwSession);
+  if( CKR_OK != *pError ) {
+    goto loser;
+  }
+#endif /* DEBUG */
+
+  return fwSession;
+
+ loser:
+  if (arena) {
+    if (fwSession &&   fwSession->sessionObjectHash) {
+      (void)nssCKFWHash_Destroy(fwSession->sessionObjectHash);
+    }
+    NSSArena_Destroy(arena);
+  }
+
+  return (NSSCKFWSession *)NULL;
+}
+
+static void
+nss_ckfw_session_object_destroy_iterator
+(
+  const void *key,
+  void *value,
+  void *closure
+)
+{
+  NSSCKFWObject *fwObject = (NSSCKFWObject *)value;
+  nssCKFWObject_Finalize(fwObject, PR_TRUE);
+}
+
+/*
+ * nssCKFWSession_Destroy
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_Destroy
+(
+  NSSCKFWSession *fwSession,
+  CK_BBOOL removeFromTokenHash
+)
+{
+  CK_RV error = CKR_OK;
+  nssCKFWHash *sessionObjectHash;
+  NSSCKFWCryptoOperationState i;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+#endif /* NSSDEBUG */
+
+  if( removeFromTokenHash ) {
+    error = nssCKFWToken_RemoveSession(fwSession->fwToken, fwSession);
+  }
+
+  /*
+   * Invalidate session objects
+   */
+
+  sessionObjectHash = fwSession->sessionObjectHash;
+  fwSession->sessionObjectHash = (nssCKFWHash *)NULL;
+
+  nssCKFWHash_Iterate(sessionObjectHash, 
+                      nss_ckfw_session_object_destroy_iterator, 
+                      (void *)NULL);
+
+  for (i=0; i < NSSCKFWCryptoOperationState_Max; i++) {
+    if (fwSession->fwOperationArray[i]) {
+      nssCKFWCryptoOperation_Destroy(fwSession->fwOperationArray[i]);
+    }
+  }
+
+#ifdef DEBUG
+  (void)session_remove_pointer(fwSession);
+#endif /* DEBUG */
+  (void)nssCKFWHash_Destroy(sessionObjectHash);
+  NSSArena_Destroy(fwSession->arena);
+
+  return error;
+}
+
+/*
+ * nssCKFWSession_GetMDSession
+ *
+ */
+NSS_IMPLEMENT NSSCKMDSession *
+nssCKFWSession_GetMDSession
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return (NSSCKMDSession *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  return fwSession->mdSession;
+}
+
+/*
+ * nssCKFWSession_GetArena
+ *
+ */
+NSS_IMPLEMENT NSSArena *
+nssCKFWSession_GetArena
+(
+  NSSCKFWSession *fwSession,
+  CK_RV *pError
+)
+{
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (NSSArena *)NULL;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != *pError ) {
+    return (NSSArena *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  return fwSession->arena;
+}
+
+/*
+ * nssCKFWSession_CallNotification
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_CallNotification
+(
+  NSSCKFWSession *fwSession,
+  CK_NOTIFICATION event
+)
+{
+  CK_RV error = CKR_OK;
+  CK_SESSION_HANDLE handle;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+#endif /* NSSDEBUG */
+
+  if( (CK_NOTIFY)NULL == fwSession->Notify ) {
+    return CKR_OK;
+  }
+
+  handle = nssCKFWInstance_FindSessionHandle(fwSession->fwInstance, fwSession);
+  if( (CK_SESSION_HANDLE)0 == handle ) {
+    return CKR_GENERAL_ERROR;
+  }
+
+  error = fwSession->Notify(handle, event, fwSession->pApplication);
+
+  return error;
+}
+
+/*
+ * nssCKFWSession_IsRWSession
+ *
+ */
+NSS_IMPLEMENT CK_BBOOL
+nssCKFWSession_IsRWSession
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CK_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  return fwSession->rw;
+}
+
+/*
+ * nssCKFWSession_IsSO
+ *
+ */
+NSS_IMPLEMENT CK_BBOOL
+nssCKFWSession_IsSO
+(
+  NSSCKFWSession *fwSession
+)
+{
+  CK_STATE state;
+
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CK_FALSE;
+  }
+#endif /* NSSDEBUG */
+
+  state = nssCKFWToken_GetSessionState(fwSession->fwToken);
+  switch( state ) {
+  case CKS_RO_PUBLIC_SESSION:
+  case CKS_RO_USER_FUNCTIONS:
+  case CKS_RW_PUBLIC_SESSION:
+  case CKS_RW_USER_FUNCTIONS:
+    return CK_FALSE;
+  case CKS_RW_SO_FUNCTIONS:
+    return CK_TRUE;
+  default:
+    return CK_FALSE;
+  }
+}
+
+/*
+ * nssCKFWSession_GetFWSlot
+ *
+ */
+NSS_IMPLEMENT NSSCKFWSlot *
+nssCKFWSession_GetFWSlot
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return (NSSCKFWSlot *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  return nssCKFWToken_GetFWSlot(fwSession->fwToken);
+}
+
+/*
+ * nssCFKWSession_GetSessionState
+ *
+ */
+NSS_IMPLEMENT CK_STATE
+nssCKFWSession_GetSessionState
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CKS_RO_PUBLIC_SESSION; /* whatever */
+  }
+#endif /* NSSDEBUG */
+
+  return nssCKFWToken_GetSessionState(fwSession->fwToken);
+}
+
+/*
+ * nssCKFWSession_SetFWFindObjects
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_SetFWFindObjects
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWFindObjects *fwFindObjects
+)
+{
+#ifdef NSSDEBUG
+  CK_RV error = CKR_OK;
+#endif /* NSSDEBUG */
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  /* fwFindObjects may be null */
+#endif /* NSSDEBUG */
+
+  if ((fwSession->fwFindObjects) &&
+      (fwFindObjects)) {
+    return CKR_OPERATION_ACTIVE;
+  }
+
+  fwSession->fwFindObjects = fwFindObjects;
+
+  return CKR_OK;
+}
+
+/*
+ * nssCKFWSession_GetFWFindObjects
+ *
+ */
+NSS_IMPLEMENT NSSCKFWFindObjects *
+nssCKFWSession_GetFWFindObjects
+(
+  NSSCKFWSession *fwSession,
+  CK_RV *pError
+)
+{
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (NSSCKFWFindObjects *)NULL;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != *pError ) {
+    return (NSSCKFWFindObjects *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  if (!fwSession->fwFindObjects) {
+    *pError = CKR_OPERATION_NOT_INITIALIZED;
+    return (NSSCKFWFindObjects *)NULL;
+  }
+
+  return fwSession->fwFindObjects;
+}
+
+/*
+ * nssCKFWSession_SetMDSession
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_SetMDSession
+(
+  NSSCKFWSession *fwSession,
+  NSSCKMDSession *mdSession
+)
+{
+#ifdef NSSDEBUG
+  CK_RV error = CKR_OK;
+#endif /* NSSDEBUG */
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!mdSession) {
+    return CKR_ARGUMENTS_BAD;
+  }
+#endif /* NSSDEBUG */
+
+  if (fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+
+  fwSession->mdSession = mdSession;
+
+  return CKR_OK;
+}
+
+/*
+ * nssCKFWSession_SetHandle
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_SetHandle
+(
+  NSSCKFWSession *fwSession,
+  CK_SESSION_HANDLE hSession
+)
+{
+#ifdef NSSDEBUG
+  CK_RV error = CKR_OK;
+#endif /* NSSDEBUG */
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+#endif /* NSSDEBUG */
+
+  if( (CK_SESSION_HANDLE)0 != fwSession->hSession ) {
+    return CKR_GENERAL_ERROR;
+  }
+
+  fwSession->hSession = hSession;
+
+  return CKR_OK;
+}
+
+/*
+ * nssCKFWSession_GetHandle
+ *
+ */
+NSS_IMPLEMENT CK_SESSION_HANDLE
+nssCKFWSession_GetHandle
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return NULL;
+  }
+#endif /* NSSDEBUG */
+
+  return fwSession->hSession;
+}
+
+/*
+ * nssCKFWSession_RegisterSessionObject
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_RegisterSessionObject
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWObject *fwObject
+)
+{
+  CK_RV rv = CKR_OK;
+
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  if (fwSession->sessionObjectHash) {
+    rv = nssCKFWHash_Add(fwSession->sessionObjectHash, fwObject, fwObject);
+  }
+
+  return rv;
+}
+
+/*
+ * nssCKFWSession_DeregisterSessionObject
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_DeregisterSessionObject
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWObject *fwObject
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  if (fwSession->sessionObjectHash) {
+    nssCKFWHash_Remove(fwSession->sessionObjectHash, fwObject);
+  }
+
+  return CKR_OK;
+}
+
+/*
+ * nssCKFWSession_GetDeviceError
+ *
+ */
+NSS_IMPLEMENT CK_ULONG
+nssCKFWSession_GetDeviceError
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef NSSDEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return (CK_ULONG)0;
+  }
+
+  if (!fwSession->mdSession) {
+    return (CK_ULONG)0;
+  }
+#endif /* NSSDEBUG */
+
+  if (!fwSession->mdSession->GetDeviceError) {
+    return (CK_ULONG)0;
+  }
+
+  return fwSession->mdSession->GetDeviceError(fwSession->mdSession, 
+    fwSession, fwSession->mdToken, fwSession->fwToken, 
+    fwSession->mdInstance, fwSession->fwInstance);
+}
+
+/*
+ * nssCKFWSession_Login
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_Login
+(
+  NSSCKFWSession *fwSession,
+  CK_USER_TYPE userType,
+  NSSItem *pin
+)
+{
+  CK_RV error = CKR_OK;
+  CK_STATE oldState;
+  CK_STATE newState;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  switch( userType ) {
+  case CKU_SO:
+  case CKU_USER:
+    break;
+  default:
+    return CKR_USER_TYPE_INVALID;
+  }
+
+  if (!pin) {
+    if( CK_TRUE != nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken) ) {
+      return CKR_ARGUMENTS_BAD;
+    }
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  oldState = nssCKFWToken_GetSessionState(fwSession->fwToken);
+
+  /*
+   * It's not clear what happens when you're already logged in.
+   * I'll just fail; but if we decide to change, the logic is
+   * all right here.
+   */
+
+  if( CKU_SO == userType ) {
+    switch( oldState ) {
+    case CKS_RO_PUBLIC_SESSION:      
+      /*
+       * There's no such thing as a read-only security officer
+       * session, so fail.  The error should be CKR_SESSION_READ_ONLY,
+       * except that C_Login isn't defined to return that.  So we'll
+       * do CKR_SESSION_READ_ONLY_EXISTS, which is what is documented.
+       */
+      return CKR_SESSION_READ_ONLY_EXISTS;
+    case CKS_RO_USER_FUNCTIONS:
+      return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+    case CKS_RW_PUBLIC_SESSION:
+      newState = CKS_RW_SO_FUNCTIONS;
+      break;
+    case CKS_RW_USER_FUNCTIONS:
+      return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+    case CKS_RW_SO_FUNCTIONS:
+      return CKR_USER_ALREADY_LOGGED_IN;
+    default:
+      return CKR_GENERAL_ERROR;
+    }
+  } else /* CKU_USER == userType */ {
+    switch( oldState ) {
+    case CKS_RO_PUBLIC_SESSION:      
+      newState = CKS_RO_USER_FUNCTIONS;
+      break;
+    case CKS_RO_USER_FUNCTIONS:
+      return CKR_USER_ALREADY_LOGGED_IN;
+    case CKS_RW_PUBLIC_SESSION:
+      newState = CKS_RW_USER_FUNCTIONS;
+      break;
+    case CKS_RW_USER_FUNCTIONS:
+      return CKR_USER_ALREADY_LOGGED_IN;
+    case CKS_RW_SO_FUNCTIONS:
+      return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+    default:
+      return CKR_GENERAL_ERROR;
+    }
+  }
+
+  /*
+   * So now we're in one of three cases:
+   *
+   * Old == CKS_RW_PUBLIC_SESSION, New == CKS_RW_SO_FUNCTIONS;
+   * Old == CKS_RW_PUBLIC_SESSION, New == CKS_RW_USER_FUNCTIONS;
+   * Old == CKS_RO_PUBLIC_SESSION, New == CKS_RO_USER_FUNCTIONS;
+   */
+
+  if (!fwSession->mdSession->Login) {
+    /*
+     * The Module doesn't want to be informed (or check the pin)
+     * it'll just rely on the Framework as needed.
+     */
+    ;
+  } else {
+    error = fwSession->mdSession->Login(fwSession->mdSession, fwSession,
+      fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+      fwSession->fwInstance, userType, pin, oldState, newState);
+    if( CKR_OK != error ) {
+      return error;
+    }
+  }
+
+  (void)nssCKFWToken_SetSessionState(fwSession->fwToken, newState);
+  return CKR_OK;
+}
+
+/*
+ * nssCKFWSession_Logout
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_Logout
+(
+  NSSCKFWSession *fwSession
+)
+{
+  CK_RV error = CKR_OK;
+  CK_STATE oldState;
+  CK_STATE newState;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  oldState = nssCKFWToken_GetSessionState(fwSession->fwToken);
+
+  switch( oldState ) {
+  case CKS_RO_PUBLIC_SESSION:
+    return CKR_USER_NOT_LOGGED_IN;
+  case CKS_RO_USER_FUNCTIONS:
+    newState = CKS_RO_PUBLIC_SESSION;
+    break;
+  case CKS_RW_PUBLIC_SESSION:
+    return CKR_USER_NOT_LOGGED_IN;
+  case CKS_RW_USER_FUNCTIONS:
+    newState = CKS_RW_PUBLIC_SESSION;
+    break;
+  case CKS_RW_SO_FUNCTIONS:
+    newState = CKS_RW_PUBLIC_SESSION;
+    break;
+  default:
+    return CKR_GENERAL_ERROR;
+  }
+
+  /*
+   * So now we're in one of three cases:
+   *
+   * Old == CKS_RW_SO_FUNCTIONS,   New == CKS_RW_PUBLIC_SESSION;
+   * Old == CKS_RW_USER_FUNCTIONS, New == CKS_RW_PUBLIC_SESSION;
+   * Old == CKS_RO_USER_FUNCTIONS, New == CKS_RO_PUBLIC_SESSION;
+   */
+
+  if (!fwSession->mdSession->Logout) {
+    /*
+     * The Module doesn't want to be informed.  Okay.
+     */
+    ;
+  } else {
+    error = fwSession->mdSession->Logout(fwSession->mdSession, fwSession,
+      fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+      fwSession->fwInstance, oldState, newState);
+    if( CKR_OK != error ) {
+      /*
+       * Now what?!  A failure really should end up with the Framework
+       * considering it logged out, right?
+       */
+      ;
+    }
+  }
+
+  (void)nssCKFWToken_SetSessionState(fwSession->fwToken, newState);
+  return error;
+}
+
+/*
+ * nssCKFWSession_InitPIN
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_InitPIN
+(
+  NSSCKFWSession *fwSession,
+  NSSItem *pin
+)
+{
+  CK_RV error = CKR_OK;
+  CK_STATE state;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  state = nssCKFWToken_GetSessionState(fwSession->fwToken);
+  if( CKS_RW_SO_FUNCTIONS != state ) {
+    return CKR_USER_NOT_LOGGED_IN;
+  }
+
+  if (!pin) {
+    CK_BBOOL has = nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken);
+    if( CK_TRUE != has ) {
+      return CKR_ARGUMENTS_BAD;
+    }
+  }
+
+  if (!fwSession->mdSession->InitPIN) {
+    return CKR_TOKEN_WRITE_PROTECTED;
+  }
+
+  error = fwSession->mdSession->InitPIN(fwSession->mdSession, fwSession,
+    fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+    fwSession->fwInstance, pin);
+
+  return error;
+}
+
+/*
+ * nssCKFWSession_SetPIN
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_SetPIN
+(
+  NSSCKFWSession *fwSession,
+  NSSItem *newPin,
+  NSSItem *oldPin
+)
+{
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  if (!newPin) {
+    CK_BBOOL has = nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken);
+    if( CK_TRUE != has ) {
+      return CKR_ARGUMENTS_BAD;
+    }
+  }
+
+  if (!oldPin) {
+    CK_BBOOL has = nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken);
+    if( CK_TRUE != has ) {
+      return CKR_ARGUMENTS_BAD;
+    }
+  }
+
+  if (!fwSession->mdSession->SetPIN) {
+    return CKR_TOKEN_WRITE_PROTECTED;
+  }
+
+  error = fwSession->mdSession->SetPIN(fwSession->mdSession, fwSession,
+    fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+    fwSession->fwInstance, newPin, oldPin);
+
+  return error;
+}
+
+/*
+ * nssCKFWSession_GetOperationStateLen
+ *
+ */
+NSS_IMPLEMENT CK_ULONG
+nssCKFWSession_GetOperationStateLen
+(
+  NSSCKFWSession *fwSession,
+  CK_RV *pError
+)
+{
+  CK_ULONG mdAmt;
+  CK_ULONG fwAmt;
+
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (CK_ULONG)0;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != *pError ) {
+    return (CK_ULONG)0;
+  }
+
+  if (!fwSession->mdSession) {
+    *pError = CKR_GENERAL_ERROR;
+    return (CK_ULONG)0;
+  }
+#endif /* NSSDEBUG */
+
+  if (!fwSession->mdSession->GetOperationStateLen) {
+    *pError = CKR_STATE_UNSAVEABLE;
+    return (CK_ULONG)0;
+  }
+
+  /*
+   * We could check that the session is actually in some state..
+   */
+
+  mdAmt = fwSession->mdSession->GetOperationStateLen(fwSession->mdSession,
+    fwSession, fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+    fwSession->fwInstance, pError);
+
+  if( ((CK_ULONG)0 == mdAmt) && (CKR_OK != *pError) ) {
+    return (CK_ULONG)0;
+  }
+
+  /*
+   * Add a bit of sanity-checking
+   */
+  fwAmt = mdAmt + 2*sizeof(CK_ULONG);
+
+  return fwAmt;
+}
+
+/*
+ * nssCKFWSession_GetOperationState
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_GetOperationState
+(
+  NSSCKFWSession *fwSession,
+  NSSItem *buffer
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG fwAmt;
+  CK_ULONG *ulBuffer;
+  NSSItem i2;
+  CK_ULONG n, i;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!buffer) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!buffer->data) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  if (!fwSession->mdSession->GetOperationState) {
+    return CKR_STATE_UNSAVEABLE;
+  }
+
+  /*
+   * Sanity-check the caller's buffer.
+   */
+
+  error = CKR_OK;
+  fwAmt = nssCKFWSession_GetOperationStateLen(fwSession, &error);
+  if( ((CK_ULONG)0 == fwAmt) && (CKR_OK != error) ) {
+    return error;
+  }
+
+  if( buffer->size < fwAmt ) {
+    return CKR_BUFFER_TOO_SMALL;
+  }
+
+  ulBuffer = (CK_ULONG *)buffer->data;
+
+  i2.size = buffer->size - 2*sizeof(CK_ULONG);
+  i2.data = (void *)&ulBuffer[2];
+
+  error = fwSession->mdSession->GetOperationState(fwSession->mdSession,
+    fwSession, fwSession->mdToken, fwSession->fwToken, 
+    fwSession->mdInstance, fwSession->fwInstance, &i2);
+
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  /*
+   * Add a little integrety/identity check.  
+   * NOTE: right now, it's pretty stupid.  
+   * A CRC or something would be better.
+   */
+
+  ulBuffer[0] = 0x434b4657; /* CKFW */
+  ulBuffer[1] = 0;
+  n = i2.size/sizeof(CK_ULONG);
+  for( i = 0; i < n; i++ ) {
+    ulBuffer[1] ^= ulBuffer[2+i];
+  }
+
+  return CKR_OK;
+}
+
+/*
+ * nssCKFWSession_SetOperationState
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_SetOperationState
+(
+  NSSCKFWSession *fwSession,
+  NSSItem *state,
+  NSSCKFWObject *encryptionKey,
+  NSSCKFWObject *authenticationKey
+)
+{
+  CK_RV error = CKR_OK;
+  CK_ULONG *ulBuffer;
+  CK_ULONG n, i;
+  CK_ULONG x;
+  NSSItem s;
+  NSSCKMDObject *mdek;
+  NSSCKMDObject *mdak;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!state) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!state->data) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (encryptionKey) {
+    error = nssCKFWObject_verifyPointer(encryptionKey);
+    if( CKR_OK != error ) {
+      return error;
+    }
+  }
+
+  if (authenticationKey) {
+    error = nssCKFWObject_verifyPointer(authenticationKey);
+    if( CKR_OK != error ) {
+      return error;
+    }
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  ulBuffer = (CK_ULONG *)state->data;
+  if( 0x43b4657 != ulBuffer[0] ) {
+    return CKR_SAVED_STATE_INVALID;
+  }
+  n = (state->size / sizeof(CK_ULONG)) - 2;
+  x = (CK_ULONG)0;
+  for( i = 0; i < n; i++ ) {
+    x ^= ulBuffer[2+i];
+  }
+
+  if( x != ulBuffer[1] ) {
+    return CKR_SAVED_STATE_INVALID;
+  }
+
+  if (!fwSession->mdSession->SetOperationState) {
+    return CKR_GENERAL_ERROR;
+  }
+
+  s.size = state->size - 2*sizeof(CK_ULONG);
+  s.data = (void *)&ulBuffer[2];
+
+  if (encryptionKey) {
+    mdek = nssCKFWObject_GetMDObject(encryptionKey);
+  } else {
+    mdek = (NSSCKMDObject *)NULL;
+  }
+
+  if (authenticationKey) {
+    mdak = nssCKFWObject_GetMDObject(authenticationKey);
+  } else {
+    mdak = (NSSCKMDObject *)NULL;
+  }
+
+  error = fwSession->mdSession->SetOperationState(fwSession->mdSession, 
+    fwSession, fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+    fwSession->fwInstance, &s, mdek, encryptionKey, mdak, authenticationKey);
+
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  /*
+   * Here'd we restore any session data
+   */
+  
+  return CKR_OK;
+}
+
+static CK_BBOOL
+nss_attributes_form_token_object
+(
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulAttributeCount
+)
+{
+  CK_ULONG i;
+  CK_BBOOL rv;
+
+  for( i = 0; i < ulAttributeCount; i++ ) {
+    if( CKA_TOKEN == pTemplate[i].type ) {
+      /* If we sanity-check, we can remove this sizeof check */
+      if( sizeof(CK_BBOOL) == pTemplate[i].ulValueLen ) {
+        (void)nsslibc_memcpy(&rv, pTemplate[i].pValue, sizeof(CK_BBOOL));
+        return rv;
+      } else {
+        return CK_FALSE;
+      }
+    }
+  }
+
+  return CK_FALSE;
+}
+
+/*
+ * nssCKFWSession_CreateObject
+ *
+ */
+NSS_IMPLEMENT NSSCKFWObject *
+nssCKFWSession_CreateObject
+(
+  NSSCKFWSession *fwSession,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulAttributeCount,
+  CK_RV *pError
+)
+{
+  NSSArena *arena;
+  NSSCKMDObject *mdObject;
+  NSSCKFWObject *fwObject;
+  CK_BBOOL isTokenObject;
+
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (NSSCKFWObject *)NULL;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != pError ) {
+    return (NSSCKFWObject *)NULL;
+  }
+
+  if( (CK_ATTRIBUTE_PTR)NULL == pTemplate ) {
+    *pError = CKR_ARGUMENTS_BAD;
+    return (NSSCKFWObject *)NULL;
+  }
+
+  if (!fwSession->mdSession) {
+    *pError = CKR_GENERAL_ERROR;
+    return (NSSCKFWObject *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  /*
+   * Here would be an excellent place to sanity-check the object.
+   */
+
+  isTokenObject = nss_attributes_form_token_object(pTemplate, ulAttributeCount);
+  if( CK_TRUE == isTokenObject ) {
+    /* === TOKEN OBJECT === */
+
+    if (!fwSession->mdSession->CreateObject) {
+      *pError = CKR_TOKEN_WRITE_PROTECTED;
+      return (NSSCKFWObject *)NULL;
+    }
+
+    arena = nssCKFWToken_GetArena(fwSession->fwToken, pError);
+    if (!arena) {
+      if( CKR_OK == *pError ) {
+        *pError = CKR_GENERAL_ERROR;
+      }
+      return (NSSCKFWObject *)NULL;
+    }
+
+    goto callmdcreateobject;
+  } else {
+    /* === SESSION OBJECT === */
+
+    arena = nssCKFWSession_GetArena(fwSession, pError);
+    if (!arena) {
+      if( CKR_OK == *pError ) {
+        *pError = CKR_GENERAL_ERROR;
+      }
+      return (NSSCKFWObject *)NULL;
+    }
+
+    if( CK_TRUE == nssCKFWInstance_GetModuleHandlesSessionObjects(
+                     fwSession->fwInstance) ) {
+      /* --- module handles the session object -- */
+
+      if (!fwSession->mdSession->CreateObject) {
+        *pError = CKR_GENERAL_ERROR;
+        return (NSSCKFWObject *)NULL;
+      }
+      
+      goto callmdcreateobject;
+    } else {
+      /* --- framework handles the session object -- */
+      mdObject = nssCKMDSessionObject_Create(fwSession->fwToken, 
+        arena, pTemplate, ulAttributeCount, pError);
+      goto gotmdobject;
+    }
+  }
+
+ callmdcreateobject:
+  mdObject = fwSession->mdSession->CreateObject(fwSession->mdSession,
+    fwSession, fwSession->mdToken, fwSession->fwToken,
+    fwSession->mdInstance, fwSession->fwInstance, arena, pTemplate,
+    ulAttributeCount, pError);
+
+ gotmdobject:
+  if (!mdObject) {
+    if( CKR_OK == *pError ) {
+      *pError = CKR_GENERAL_ERROR;
+    }
+    return (NSSCKFWObject *)NULL;
+  }
+
+  fwObject = nssCKFWObject_Create(arena, mdObject, 
+    isTokenObject ? NULL : fwSession, 
+    fwSession->fwToken, fwSession->fwInstance, pError);
+  if (!fwObject) {
+    if( CKR_OK == *pError ) {
+      *pError = CKR_GENERAL_ERROR;
+    }
+    
+    if (mdObject->Destroy) {
+      (void)mdObject->Destroy(mdObject, (NSSCKFWObject *)NULL,
+        fwSession->mdSession, fwSession, fwSession->mdToken,
+        fwSession->fwToken, fwSession->mdInstance, fwSession->fwInstance);
+    }
+    
+    return (NSSCKFWObject *)NULL;
+  }
+
+  if( CK_FALSE == isTokenObject ) {
+    if( CK_FALSE == nssCKFWHash_Exists(fwSession->sessionObjectHash, fwObject) ) {
+      *pError = nssCKFWHash_Add(fwSession->sessionObjectHash, fwObject, fwObject);
+      if( CKR_OK != *pError ) {
+        nssCKFWObject_Finalize(fwObject, PR_TRUE);
+        return (NSSCKFWObject *)NULL;
+      }
+    }
+  }
+  
+  return fwObject;
+}
+
+/*
+ * nssCKFWSession_CopyObject
+ *
+ */
+NSS_IMPLEMENT NSSCKFWObject *
+nssCKFWSession_CopyObject
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWObject *fwObject,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulAttributeCount,
+  CK_RV *pError
+)
+{
+  CK_BBOOL oldIsToken;
+  CK_BBOOL newIsToken;
+  CK_ULONG i;
+  NSSCKFWObject *rv;
+
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (NSSCKFWObject *)NULL;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != *pError ) {
+    return (NSSCKFWObject *)NULL;
+  }
+
+  *pError = nssCKFWObject_verifyPointer(fwObject);
+  if( CKR_OK != *pError ) {
+    return (NSSCKFWObject *)NULL;
+  }
+
+  if (!fwSession->mdSession) {
+    *pError = CKR_GENERAL_ERROR;
+    return (NSSCKFWObject *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  /*
+   * Sanity-check object
+   */
+
+  if (!fwObject) {
+    *pError = CKR_ARGUMENTS_BAD;
+    return (NSSCKFWObject *)NULL;
+  }
+
+  oldIsToken = nssCKFWObject_IsTokenObject(fwObject);
+
+  newIsToken = oldIsToken;
+  for( i = 0; i < ulAttributeCount; i++ ) {
+    if( CKA_TOKEN == pTemplate[i].type ) {
+      /* Since we sanity-checked the object, we know this is the right size. */
+      (void)nsslibc_memcpy(&newIsToken, pTemplate[i].pValue, sizeof(CK_BBOOL));
+      break;
+    }
+  }
+
+  /*
+   * If the Module handles its session objects, or if both the new
+   * and old object are token objects, use CopyObject if it exists.
+   */
+
+  if ((fwSession->mdSession->CopyObject) &&
+      (((CK_TRUE == oldIsToken) && (CK_TRUE == newIsToken)) ||
+       (CK_TRUE == nssCKFWInstance_GetModuleHandlesSessionObjects(
+                     fwSession->fwInstance))) ) {
+    /* use copy object */
+    NSSArena *arena;
+    NSSCKMDObject *mdOldObject;
+    NSSCKMDObject *mdObject;
+
+    mdOldObject = nssCKFWObject_GetMDObject(fwObject);
+
+    if( CK_TRUE == newIsToken ) {
+      arena = nssCKFWToken_GetArena(fwSession->fwToken, pError);
+    } else {
+      arena = nssCKFWSession_GetArena(fwSession, pError);
+    }
+    if (!arena) {
+      if( CKR_OK == *pError ) {
+        *pError = CKR_GENERAL_ERROR;
+      }
+      return (NSSCKFWObject *)NULL;
+    }
+
+    mdObject = fwSession->mdSession->CopyObject(fwSession->mdSession,
+      fwSession, fwSession->mdToken, fwSession->fwToken,
+      fwSession->mdInstance, fwSession->fwInstance, mdOldObject,
+      fwObject, arena, pTemplate, ulAttributeCount, pError);
+    if (!mdObject) {
+      if( CKR_OK == *pError ) {
+        *pError = CKR_GENERAL_ERROR;
+      }
+      return (NSSCKFWObject *)NULL;
+    }
+
+    rv = nssCKFWObject_Create(arena, mdObject, 
+      newIsToken ? NULL : fwSession,
+      fwSession->fwToken, fwSession->fwInstance, pError);
+
+    if( CK_FALSE == newIsToken ) {
+      if( CK_FALSE == nssCKFWHash_Exists(fwSession->sessionObjectHash, rv) ) {
+        *pError = nssCKFWHash_Add(fwSession->sessionObjectHash, rv, rv);
+        if( CKR_OK != *pError ) {
+          nssCKFWObject_Finalize(rv, PR_TRUE);
+          return (NSSCKFWObject *)NULL;
+        }
+      }
+    }
+
+    return rv;
+  } else {
+    /* use create object */
+    NSSArena *tmpArena;
+    CK_ATTRIBUTE_PTR newTemplate;
+    CK_ULONG i, j, n, newLength, k;
+    CK_ATTRIBUTE_TYPE_PTR oldTypes;
+    NSSCKFWObject *rv;
+    
+    n = nssCKFWObject_GetAttributeCount(fwObject, pError);
+    if( (0 == n) && (CKR_OK != *pError) ) {
+      return (NSSCKFWObject *)NULL;
+    }
+
+    tmpArena = NSSArena_Create();
+    if (!tmpArena) {
+      *pError = CKR_HOST_MEMORY;
+      return (NSSCKFWObject *)NULL;
+    }
+
+    oldTypes = nss_ZNEWARRAY(tmpArena, CK_ATTRIBUTE_TYPE, n);
+    if( (CK_ATTRIBUTE_TYPE_PTR)NULL == oldTypes ) {
+      NSSArena_Destroy(tmpArena);
+      *pError = CKR_HOST_MEMORY;
+      return (NSSCKFWObject *)NULL;
+    }
+
+    *pError = nssCKFWObject_GetAttributeTypes(fwObject, oldTypes, n);
+    if( CKR_OK != *pError ) {
+      NSSArena_Destroy(tmpArena);
+      return (NSSCKFWObject *)NULL;
+    }
+
+    newLength = n;
+    for( i = 0; i < ulAttributeCount; i++ ) {
+      for( j = 0; j < n; j++ ) {
+        if( oldTypes[j] == pTemplate[i].type ) {
+          if( (CK_VOID_PTR)NULL == pTemplate[i].pValue ) {
+            /* Removing the attribute */
+            newLength--;
+          }
+          break;
+        }
+      }
+      if( j == n ) {
+        /* Not found */
+        newLength++;
+      }
+    }
+
+    newTemplate = nss_ZNEWARRAY(tmpArena, CK_ATTRIBUTE, newLength);
+    if( (CK_ATTRIBUTE_PTR)NULL == newTemplate ) {
+      NSSArena_Destroy(tmpArena);
+      *pError = CKR_HOST_MEMORY;
+      return (NSSCKFWObject *)NULL;
+    }
+
+    k = 0;
+    for( j = 0; j < n; j++ ) {
+      for( i = 0; i < ulAttributeCount; i++ ) {
+        if( oldTypes[j] == pTemplate[i].type ) {
+          if( (CK_VOID_PTR)NULL == pTemplate[i].pValue ) {
+            /* This attribute is being deleted */
+            ;
+          } else {
+            /* This attribute is being replaced */
+            newTemplate[k].type = pTemplate[i].type;
+            newTemplate[k].pValue = pTemplate[i].pValue;
+            newTemplate[k].ulValueLen = pTemplate[i].ulValueLen;
+            k++;
+          }
+          break;
+        }
+      }
+      if( i == ulAttributeCount ) {
+        /* This attribute is being copied over from the old object */
+        NSSItem item, *it;
+        item.size = 0;
+        item.data = (void *)NULL;
+        it = nssCKFWObject_GetAttribute(fwObject, oldTypes[j],
+          &item, tmpArena, pError);
+        if (!it) {
+          if( CKR_OK == *pError ) {
+            *pError = CKR_GENERAL_ERROR;
+          }
+          NSSArena_Destroy(tmpArena);
+          return (NSSCKFWObject *)NULL;
+        }
+        newTemplate[k].type = oldTypes[j];
+        newTemplate[k].pValue = it->data;
+        newTemplate[k].ulValueLen = it->size;
+        k++;
+      }
+    }
+    /* assert that k == newLength */
+
+    rv = nssCKFWSession_CreateObject(fwSession, newTemplate, newLength, pError);
+    if (!rv) {
+      if( CKR_OK == *pError ) {
+        *pError = CKR_GENERAL_ERROR;
+      }
+      NSSArena_Destroy(tmpArena);
+      return (NSSCKFWObject *)NULL;
+    }
+
+    NSSArena_Destroy(tmpArena);
+    return rv;
+  }
+}
+
+/*
+ * nssCKFWSession_FindObjectsInit
+ *
+ */
+NSS_IMPLEMENT NSSCKFWFindObjects *
+nssCKFWSession_FindObjectsInit
+(
+  NSSCKFWSession *fwSession,
+  CK_ATTRIBUTE_PTR pTemplate,
+  CK_ULONG ulAttributeCount,
+  CK_RV *pError
+)
+{
+  NSSCKMDFindObjects *mdfo1 = (NSSCKMDFindObjects *)NULL;
+  NSSCKMDFindObjects *mdfo2 = (NSSCKMDFindObjects *)NULL;
+
+#ifdef NSSDEBUG
+  if (!pError) {
+    return (NSSCKFWFindObjects *)NULL;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != *pError ) {
+    return (NSSCKFWFindObjects *)NULL;
+  }
+
+  if( ((CK_ATTRIBUTE_PTR)NULL == pTemplate) && (ulAttributeCount != 0) ) {
+    *pError = CKR_ARGUMENTS_BAD;
+    return (NSSCKFWFindObjects *)NULL;
+  }
+
+  if (!fwSession->mdSession) {
+    *pError = CKR_GENERAL_ERROR;
+    return (NSSCKFWFindObjects *)NULL;
+  }
+#endif /* NSSDEBUG */
+
+  if( CK_TRUE != nssCKFWInstance_GetModuleHandlesSessionObjects(
+                   fwSession->fwInstance) ) {
+    CK_ULONG i;
+
+    /*
+     * Does the search criteria restrict us to token or session
+     * objects?
+     */
+
+    for( i = 0; i < ulAttributeCount; i++ ) {
+      if( CKA_TOKEN == pTemplate[i].type ) {
+        /* Yes, it does. */
+        CK_BBOOL isToken;
+        if( sizeof(CK_BBOOL) != pTemplate[i].ulValueLen ) {
+          *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+          return (NSSCKFWFindObjects *)NULL;
+        }
+        (void)nsslibc_memcpy(&isToken, pTemplate[i].pValue, sizeof(CK_BBOOL));
+
+        if( CK_TRUE == isToken ) {
+          /* Pass it on to the module's search routine */
+          if (!fwSession->mdSession->FindObjectsInit) {
+            goto wrap;
+          }
+
+          mdfo1 = fwSession->mdSession->FindObjectsInit(fwSession->mdSession,
+                    fwSession, fwSession->mdToken, fwSession->fwToken,
+                    fwSession->mdInstance, fwSession->fwInstance, 
+                    pTemplate, ulAttributeCount, pError);
+        } else {
+          /* Do the search ourselves */
+          mdfo1 = nssCKMDFindSessionObjects_Create(fwSession->fwToken, 
+                    pTemplate, ulAttributeCount, pError);
+        }
+
+        if (!mdfo1) {
+          if( CKR_OK == *pError ) {
+            *pError = CKR_GENERAL_ERROR;
+          }
+          return (NSSCKFWFindObjects *)NULL;
+        }
+        
+        goto wrap;
+      }
+    }
+
+    if( i == ulAttributeCount ) {
+      /* No, it doesn't.  Do a hybrid search. */
+      mdfo1 = fwSession->mdSession->FindObjectsInit(fwSession->mdSession,
+                fwSession, fwSession->mdToken, fwSession->fwToken,
+                fwSession->mdInstance, fwSession->fwInstance, 
+                pTemplate, ulAttributeCount, pError);
+
+      if (!mdfo1) {
+        if( CKR_OK == *pError ) {
+          *pError = CKR_GENERAL_ERROR;
+        }
+        return (NSSCKFWFindObjects *)NULL;
+      }
+
+      mdfo2 = nssCKMDFindSessionObjects_Create(fwSession->fwToken,
+                pTemplate, ulAttributeCount, pError);
+      if (!mdfo2) {
+        if( CKR_OK == *pError ) {
+          *pError = CKR_GENERAL_ERROR;
+        }
+        if (mdfo1->Final) {
+          mdfo1->Final(mdfo1, (NSSCKFWFindObjects *)NULL, fwSession->mdSession,
+            fwSession, fwSession->mdToken, fwSession->fwToken, 
+            fwSession->mdInstance, fwSession->fwInstance);
+        }
+        return (NSSCKFWFindObjects *)NULL;
+      }
+
+      goto wrap;
+    }
+    /*NOTREACHED*/
+  } else {
+    /* Module handles all its own objects.  Pass on to module's search */
+    mdfo1 = fwSession->mdSession->FindObjectsInit(fwSession->mdSession,
+              fwSession, fwSession->mdToken, fwSession->fwToken,
+              fwSession->mdInstance, fwSession->fwInstance, 
+              pTemplate, ulAttributeCount, pError);
+
+    if (!mdfo1) {
+      if( CKR_OK == *pError ) {
+        *pError = CKR_GENERAL_ERROR;
+      }
+      return (NSSCKFWFindObjects *)NULL;
+    }
+
+    goto wrap;
+  }
+
+ wrap:
+  return nssCKFWFindObjects_Create(fwSession, fwSession->fwToken,
+           fwSession->fwInstance, mdfo1, mdfo2, pError);
+}
+
+/*
+ * nssCKFWSession_SeedRandom
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_SeedRandom
+(
+  NSSCKFWSession *fwSession,
+  NSSItem *seed
+)
+{
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!seed) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!seed->data) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if( 0 == seed->size ) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  if (!fwSession->mdSession->SeedRandom) {
+    return CKR_RANDOM_SEED_NOT_SUPPORTED;
+  }
+
+  error = fwSession->mdSession->SeedRandom(fwSession->mdSession, fwSession,
+    fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+    fwSession->fwInstance, seed);
+
+  return error;
+}
+
+/*
+ * nssCKFWSession_GetRandom
+ *
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_GetRandom
+(
+  NSSCKFWSession *fwSession,
+  NSSItem *buffer
+)
+{
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!buffer) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!buffer->data) {
+    return CKR_ARGUMENTS_BAD;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  if (!fwSession->mdSession->GetRandom) {
+    if( CK_TRUE == nssCKFWToken_GetHasRNG(fwSession->fwToken) ) {
+      return CKR_GENERAL_ERROR;
+    } else {
+      return CKR_RANDOM_NO_RNG;
+    }
+  }
+
+  if( 0 == buffer->size ) {
+    return CKR_OK;
+  }
+
+  error = fwSession->mdSession->GetRandom(fwSession->mdSession, fwSession,
+    fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
+    fwSession->fwInstance, buffer);
+
+  return error;
+}
+
+
+/*
+ * nssCKFWSession_SetCurrentCryptoOperation
+ */
+NSS_IMPLEMENT void
+nssCKFWSession_SetCurrentCryptoOperation
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperation * fwOperation,
+  NSSCKFWCryptoOperationState state
+)
+{
+#ifdef NSSDEBUG
+  CK_RV error = CKR_OK;
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return;
+  }
+
+  if ( state >= NSSCKFWCryptoOperationState_Max) {
+    return;
+  }
+
+  if (!fwSession->mdSession) {
+    return;
+  }
+#endif /* NSSDEBUG */
+  fwSession->fwOperationArray[state] = fwOperation;
+  return;
+}
+
+/*
+ * nssCKFWSession_GetCurrentCryptoOperation
+ */
+NSS_IMPLEMENT NSSCKFWCryptoOperation *
+nssCKFWSession_GetCurrentCryptoOperation
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationState state
+)
+{
+#ifdef NSSDEBUG
+  CK_RV error = CKR_OK;
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return (NSSCKFWCryptoOperation *)NULL;
+  }
+
+  if ( state >= NSSCKFWCryptoOperationState_Max) {
+    return (NSSCKFWCryptoOperation *)NULL;
+  }
+
+  if (!fwSession->mdSession) {
+    return (NSSCKFWCryptoOperation *)NULL;
+  }
+#endif /* NSSDEBUG */
+  return fwSession->fwOperationArray[state];
+}
+
+/*
+ * nssCKFWSession_Final
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_Final
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationType type,
+  NSSCKFWCryptoOperationState state,
+  CK_BYTE_PTR  outBuf,
+  CK_ULONG_PTR outBufLen
+)
+{
+  NSSCKFWCryptoOperation *fwOperation;
+  NSSItem outputBuffer;
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  /* make sure we have a valid operation initialized */
+  fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
+  if (!fwOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* handle buffer issues, note for Verify, the type is an input buffer. */
+  if (NSSCKFWCryptoOperationType_Verify == type) {
+    if ((CK_BYTE_PTR)NULL == outBuf) {
+      error = CKR_ARGUMENTS_BAD;
+      goto done;
+    }
+  } else {
+    CK_ULONG len = nssCKFWCryptoOperation_GetFinalLength(fwOperation, &error);
+    CK_ULONG maxBufLen = *outBufLen;
+
+    if (CKR_OK != error) {
+       goto done;
+    }
+    *outBufLen = len;
+    if ((CK_BYTE_PTR)NULL == outBuf) {
+      return CKR_OK;
+    }
+
+    if (len > maxBufLen) {
+      return CKR_BUFFER_TOO_SMALL;
+    }
+  }
+  outputBuffer.data = outBuf;
+  outputBuffer.size = *outBufLen;
+
+  error = nssCKFWCryptoOperation_Final(fwOperation, &outputBuffer);
+done:
+  if (CKR_BUFFER_TOO_SMALL == error) {
+    return error;
+  }
+  /* clean up our state */
+  nssCKFWCryptoOperation_Destroy(fwOperation);
+  nssCKFWSession_SetCurrentCryptoOperation(fwSession, NULL, state);
+  return error;
+}
+
+/*
+ * nssCKFWSession_Update
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_Update
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationType type,
+  NSSCKFWCryptoOperationState state,
+  CK_BYTE_PTR  inBuf,
+  CK_ULONG     inBufLen,
+  CK_BYTE_PTR  outBuf,
+  CK_ULONG_PTR outBufLen
+)
+{
+  NSSCKFWCryptoOperation *fwOperation;
+  NSSItem inputBuffer;
+  NSSItem outputBuffer;
+  CK_ULONG len;
+  CK_ULONG maxBufLen;
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  /* make sure we have a valid operation initialized */
+  fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
+  if (!fwOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  inputBuffer.data = inBuf;
+  inputBuffer.size = inBufLen;
+
+  /* handle buffer issues, note for Verify, the type is an input buffer. */
+  len = nssCKFWCryptoOperation_GetOperationLength(fwOperation, &inputBuffer, 
+                                                  &error);
+  if (CKR_OK != error) {
+    return error;
+  }
+  maxBufLen = *outBufLen;
+
+  *outBufLen = len;
+  if ((CK_BYTE_PTR)NULL == outBuf) {
+    return CKR_OK;
+  }
+
+  if (len > maxBufLen) {
+    return CKR_BUFFER_TOO_SMALL;
+  }
+  outputBuffer.data = outBuf;
+  outputBuffer.size = *outBufLen;
+
+  return nssCKFWCryptoOperation_Update(fwOperation,
+                                       &inputBuffer, &outputBuffer);
+}
+
+/*
+ * nssCKFWSession_DigestUpdate
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_DigestUpdate
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationType type,
+  NSSCKFWCryptoOperationState state,
+  CK_BYTE_PTR  inBuf,
+  CK_ULONG     inBufLen
+)
+{
+  NSSCKFWCryptoOperation *fwOperation;
+  NSSItem inputBuffer;
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  /* make sure we have a valid operation initialized */
+  fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
+  if (!fwOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  inputBuffer.data = inBuf;
+  inputBuffer.size = inBufLen;
+
+
+  error = nssCKFWCryptoOperation_DigestUpdate(fwOperation, &inputBuffer);
+  return error;
+}
+
+/*
+ * nssCKFWSession_DigestUpdate
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_DigestKey
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWObject *fwKey
+)
+{
+  NSSCKFWCryptoOperation *fwOperation;
+  NSSItem *inputBuffer;
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  /* make sure we have a valid operation initialized */
+  fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, 
+                                 NSSCKFWCryptoOperationState_Digest);
+  if (!fwOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (NSSCKFWCryptoOperationType_Digest != 
+      nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  error = nssCKFWCryptoOperation_DigestKey(fwOperation, fwKey);
+  if (CKR_FUNCTION_FAILED != error) {
+    return error;
+  }
+
+  /* no machine depended way for this to happen, do it by hand */
+  inputBuffer=nssCKFWObject_GetAttribute(fwKey, CKA_VALUE, NULL, NULL, &error);
+  if (!inputBuffer) {
+    /* couldn't get the value, just fail then */
+    return error;
+  }
+  error = nssCKFWCryptoOperation_DigestUpdate(fwOperation, inputBuffer);
+  nssItem_Destroy(inputBuffer);
+  return error;
+}
+
+/*
+ * nssCKFWSession_UpdateFinal
+ */
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_UpdateFinal
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationType type,
+  NSSCKFWCryptoOperationState state,
+  CK_BYTE_PTR  inBuf,
+  CK_ULONG     inBufLen,
+  CK_BYTE_PTR  outBuf,
+  CK_ULONG_PTR outBufLen
+)
+{
+  NSSCKFWCryptoOperation *fwOperation;
+  NSSItem inputBuffer;
+  NSSItem outputBuffer;
+  PRBool isEncryptDecrypt;
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  /* make sure we have a valid operation initialized */
+  fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
+  if (!fwOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  inputBuffer.data = inBuf;
+  inputBuffer.size = inBufLen;
+  isEncryptDecrypt = (PRBool) ((NSSCKFWCryptoOperationType_Encrypt == type) || 
+                               (NSSCKFWCryptoOperationType_Decrypt == type)) ;
+
+  /* handle buffer issues, note for Verify, the type is an input buffer. */
+  if (NSSCKFWCryptoOperationType_Verify == type) {
+    if ((CK_BYTE_PTR)NULL == outBuf) {
+      error = CKR_ARGUMENTS_BAD;
+      goto done;
+    }
+  } else {
+    CK_ULONG maxBufLen = *outBufLen;
+    CK_ULONG len;
+
+    len = (isEncryptDecrypt) ?
+      nssCKFWCryptoOperation_GetOperationLength(fwOperation, 
+                                                &inputBuffer, &error) :
+      nssCKFWCryptoOperation_GetFinalLength(fwOperation, &error);
+
+    if (CKR_OK != error) {
+      goto done;
+    }
+
+    *outBufLen = len;
+    if ((CK_BYTE_PTR)NULL == outBuf) {
+      return CKR_OK;
+    }
+
+    if (len > maxBufLen) {
+      return CKR_BUFFER_TOO_SMALL;
+    }
+  }
+  outputBuffer.data = outBuf;
+  outputBuffer.size = *outBufLen;
+
+  error = nssCKFWCryptoOperation_UpdateFinal(fwOperation, 
+                                             &inputBuffer, &outputBuffer);
+
+  /* UpdateFinal isn't support, manually use Update and Final */
+  if (CKR_FUNCTION_FAILED == error) {
+    error = isEncryptDecrypt ? 
+      nssCKFWCryptoOperation_Update(fwOperation, &inputBuffer, &outputBuffer) :
+      nssCKFWCryptoOperation_DigestUpdate(fwOperation, &inputBuffer);
+
+    if (CKR_OK == error) {
+      error = nssCKFWCryptoOperation_Final(fwOperation, &outputBuffer);
+    }
+  }
+
+
+done:
+  if (CKR_BUFFER_TOO_SMALL == error) {
+    /* if we return CKR_BUFFER_TOO_SMALL, we the caller is not expecting.
+     * the crypto state to be freed */
+    return error;
+  }
+
+  /* clean up our state */
+  nssCKFWCryptoOperation_Destroy(fwOperation);
+  nssCKFWSession_SetCurrentCryptoOperation(fwSession, NULL, state);
+  return error;
+}
+
+NSS_IMPLEMENT CK_RV
+nssCKFWSession_UpdateCombo
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationType encryptType,
+  NSSCKFWCryptoOperationType digestType,
+  NSSCKFWCryptoOperationState digestState,
+  CK_BYTE_PTR  inBuf,
+  CK_ULONG     inBufLen,
+  CK_BYTE_PTR  outBuf,
+  CK_ULONG_PTR outBufLen
+)
+{
+  NSSCKFWCryptoOperation *fwOperation;
+  NSSCKFWCryptoOperation *fwPeerOperation;
+  NSSItem inputBuffer;
+  NSSItem outputBuffer;
+  CK_ULONG maxBufLen = *outBufLen;
+  CK_ULONG len;
+  CK_RV error = CKR_OK;
+
+#ifdef NSSDEBUG
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+
+  if (!fwSession->mdSession) {
+    return CKR_GENERAL_ERROR;
+  }
+#endif /* NSSDEBUG */
+
+  /* make sure we have a valid operation initialized */
+  fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, 
+                NSSCKFWCryptoOperationState_EncryptDecrypt);
+  if (!fwOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (encryptType != nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+  /* make sure we have a valid operation initialized */
+  fwPeerOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, 
+                  digestState);
+  if (!fwPeerOperation) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  /* make sure it's the correct type */
+  if (digestType != nssCKFWCryptoOperation_GetType(fwOperation)) {
+    return CKR_OPERATION_NOT_INITIALIZED;
+  }
+
+  inputBuffer.data = inBuf;
+  inputBuffer.size = inBufLen;
+  len = nssCKFWCryptoOperation_GetOperationLength(fwOperation, 
+                                                &inputBuffer, &error);
+  if (CKR_OK != error) {
+    return error;
+  }
+
+  *outBufLen = len;
+  if ((CK_BYTE_PTR)NULL == outBuf) {
+    return CKR_OK;
+  }
+
+  if (len > maxBufLen) {
+    return CKR_BUFFER_TOO_SMALL;
+  }
+
+  outputBuffer.data = outBuf;
+  outputBuffer.size = *outBufLen;
+
+  error = nssCKFWCryptoOperation_UpdateCombo(fwOperation, fwPeerOperation,
+                                             &inputBuffer, &outputBuffer);
+  if (CKR_FUNCTION_FAILED == error) {
+    PRBool isEncrypt = 
+           (PRBool) (NSSCKFWCryptoOperationType_Encrypt == encryptType);
+
+    if (isEncrypt) {
+      error = nssCKFWCryptoOperation_DigestUpdate(fwPeerOperation, 
+                                                  &inputBuffer);
+      if (CKR_OK != error) {
+        return error;
+      }
+    }
+    error = nssCKFWCryptoOperation_Update(fwOperation, 
+                                          &inputBuffer, &outputBuffer);
+    if (CKR_OK != error) {
+      return error;
+    }
+    if (!isEncrypt) {
+      error = nssCKFWCryptoOperation_DigestUpdate(fwPeerOperation,
+                                                  &outputBuffer);
+    }
+  }
+  return error;
+}
+
+
+/*
+ * NSSCKFWSession_GetMDSession
+ *
+ */
+
+NSS_IMPLEMENT NSSCKMDSession *
+NSSCKFWSession_GetMDSession
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef DEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return (NSSCKMDSession *)NULL;
+  }
+#endif /* DEBUG */
+
+  return nssCKFWSession_GetMDSession(fwSession);
+}
+
+/*
+ * NSSCKFWSession_GetArena
+ *
+ */
+
+NSS_IMPLEMENT NSSArena *
+NSSCKFWSession_GetArena
+(
+  NSSCKFWSession *fwSession,
+  CK_RV *pError
+)
+{
+#ifdef DEBUG
+  if (!pError) {
+    return (NSSArena *)NULL;
+  }
+
+  *pError = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != *pError ) {
+    return (NSSArena *)NULL;
+  }
+#endif /* DEBUG */
+
+  return nssCKFWSession_GetArena(fwSession, pError);
+}
+
+/*
+ * NSSCKFWSession_CallNotification
+ *
+ */
+
+NSS_IMPLEMENT CK_RV
+NSSCKFWSession_CallNotification
+(
+  NSSCKFWSession *fwSession,
+  CK_NOTIFICATION event
+)
+{
+#ifdef DEBUG
+  CK_RV error = CKR_OK;
+
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return error;
+  }
+#endif /* DEBUG */
+
+  return nssCKFWSession_CallNotification(fwSession, event);
+}
+
+/*
+ * NSSCKFWSession_IsRWSession
+ *
+ */
+
+NSS_IMPLEMENT CK_BBOOL
+NSSCKFWSession_IsRWSession
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef DEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CK_FALSE;
+  }
+#endif /* DEBUG */
+
+  return nssCKFWSession_IsRWSession(fwSession);
+}
+
+/*
+ * NSSCKFWSession_IsSO
+ *
+ */
+
+NSS_IMPLEMENT CK_BBOOL
+NSSCKFWSession_IsSO
+(
+  NSSCKFWSession *fwSession
+)
+{
+#ifdef DEBUG
+  if( CKR_OK != nssCKFWSession_verifyPointer(fwSession) ) {
+    return CK_FALSE;
+  }
+#endif /* DEBUG */
+
+  return nssCKFWSession_IsSO(fwSession);
+}
+
+NSS_IMPLEMENT NSSCKFWCryptoOperation *
+NSSCKFWSession_GetCurrentCryptoOperation
+(
+  NSSCKFWSession *fwSession,
+  NSSCKFWCryptoOperationState state
+)
+{
+#ifdef DEBUG
+  CK_RV error = CKR_OK;
+  error = nssCKFWSession_verifyPointer(fwSession);
+  if( CKR_OK != error ) {
+    return (NSSCKFWCryptoOperation *)NULL;
+  }
+
+  if ( state >= NSSCKFWCryptoOperationState_Max) {
+    return (NSSCKFWCryptoOperation *)NULL;
+  }
+#endif /* DEBUG */
+  return nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)