Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  wrap.c   Sprache: C

 
/* 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) {
        case CKR_OK: {
            PRInt32 remainingInstances;
            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);
            /* CreateObjectHandle returns CKR_GENERAL_ERROR if fwObject already
             * has a handle. This happens when another thread creates a handle
             * between our FindObjectHandle and CreateObjectHandle calls.
             */

            if (error == CKR_GENERAL_ERROR) {
                error = CKR_OK;
                phObject[i] = nssCKFWInstance_FindObjectHandle(fwInstance, fwObject);
            }
            if (error != CKR_OK || (CK_OBJECT_HANDLE)0 == phObject[i]) {
                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,
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=67 G=83

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge