Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/security/nss/lib/pk11wrap/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 69 kB image not shown  

Quelle  pk11obj.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/. */

/*
 * This file manages object type indepentent functions.
 */

#include <limits.h>
#include <stddef.h>

#include "seccomon.h"
#include "secder.h"
#include "secmod.h"
#include "secmodi.h"
#include "secmodti.h"
#include "pkcs11.h"
#include "pkcs11t.h"
#include "pk11func.h"
#include "keyhi.h"
#include "secitem.h"
#include "secerr.h"
#include "sslerr.h"

#define PK11_SEARCH_CHUNKSIZE 10

/*
 * Build a block big enough to hold the data
 */

SECItem *
PK11_BlockData(SECItem *data, unsigned long size)
{
    SECItem *newData;

    if (size == 0u)
        return NULL;

    newData = (SECItem *)PORT_Alloc(sizeof(SECItem));
    if (newData == NULL)
        return NULL;

    newData->len = (data->len + (size - 1)) / size;
    newData->len *= size;

    newData->data = (unsigned char *)PORT_ZAlloc(newData->len);
    if (newData->data == NULL) {
        PORT_Free(newData);
        return NULL;
    }
    PORT_Memset(newData->data, newData->len - data->len, newData->len);
    PORT_Memcpy(newData->data, data->data, data->len);
    return newData;
}

SECStatus
PK11_DestroyObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object)
{
    CK_RV crv;

    PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session, object);
    PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        return SECFailure;
    }
    return SECSuccess;
}

SECStatus
PK11_DestroyTokenObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object)
{
    CK_RV crv;
    SECStatus rv = SECSuccess;
    CK_SESSION_HANDLE rwsession;

    rwsession = PK11_GetRWSession(slot);
    if (rwsession == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_BAD_DATA);
        return SECFailure;
    }

    crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession, object);
    if (crv != CKR_OK) {
        rv = SECFailure;
        PORT_SetError(PK11_MapError(crv));
    }
    PK11_RestoreROSession(slot, rwsession);
    return rv;
}

/*
 * Read in a single attribute into a SECItem. Allocate space for it with
 * PORT_Alloc unless an arena is supplied. In the latter case use the arena
 * to allocate the space.
 *
 * PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but
 * does not modify its 'type' field.
 */

SECStatus
PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
                   CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result)
{
    CK_ATTRIBUTE attr = { 0, NULL, 0 };
    CK_RV crv;

    attr.type = type;

    PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
    if (crv != CKR_OK) {
        PK11_ExitSlotMonitor(slot);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    if (arena) {
        attr.pValue = PORT_ArenaAlloc(arena, attr.ulValueLen);
    } else {
        attr.pValue = PORT_Alloc(attr.ulValueLen);
    }
    if (attr.pValue == NULL) {
        PK11_ExitSlotMonitor(slot);
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
    PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        if (!arena)
            PORT_Free(attr.pValue);
        return SECFailure;
    }

    result->data = (unsigned char *)attr.pValue;
    result->len = attr.ulValueLen;

    return SECSuccess;
}

/*
 * Read in a single attribute into a Ulong.
 */

CK_ULONG
PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
                        CK_ATTRIBUTE_TYPE type)
{
    CK_ATTRIBUTE attr;
    CK_ULONG value = CK_UNAVAILABLE_INFORMATION;
    CK_RV crv;

    PK11_SETATTRS(&attr, type, &value, sizeof(value));

    PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
    PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
    }
    return value;
}

/*
 * check to see if a bool has been set.
 */

CK_BBOOL
pk11_HasAttributeSet_Lock(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
                          CK_ATTRIBUTE_TYPE type, PRBool haslock)
{
    CK_BBOOL ckvalue = CK_FALSE;
    CK_ATTRIBUTE theTemplate;
    CK_RV crv;

    /* Prepare to retrieve the attribute. */
    PK11_SETATTRS(&theTemplate, type, &ckvalue, sizeof(CK_BBOOL));

    /* Retrieve attribute value. */
    if (!haslock)
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id,
                                                 &theTemplate, 1);
    if (!haslock)
        PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return CK_FALSE;
    }

    return ckvalue;
}

CK_BBOOL
PK11_HasAttributeSet(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
                     CK_ATTRIBUTE_TYPE type, PRBool haslock)
{
    PR_ASSERT(haslock == PR_FALSE);
    return pk11_HasAttributeSet_Lock(slot, id, type, PR_FALSE);
}

/*
 * returns a full list of attributes. Allocate space for them. If an arena is
 * provided, allocate space out of the arena.
 */

CK_RV
PK11_GetAttributes(PLArenaPool *arena, PK11SlotInfo *slot,
                   CK_OBJECT_HANDLE obj, CK_ATTRIBUTE *attr, int count)
{
    int i;
    /* make pedantic happy... note that it's only used arena != NULL */
    void *mark = NULL;
    CK_RV crv;
    if (slot->session == CK_INVALID_HANDLE)
        return CKR_SESSION_HANDLE_INVALID;

    /*
     * first get all the lengths of the parameters.
     */

    PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count);
    if (crv != CKR_OK) {
        PK11_ExitSlotMonitor(slot);
        return crv;
    }

    if (arena) {
        mark = PORT_ArenaMark(arena);
        if (mark == NULL)
            return CKR_HOST_MEMORY;
    }

    /*
     * now allocate space to store the results.
     */

    for (i = 0; i < count; i++) {
        if (attr[i].ulValueLen == 0)
            continue;
        if (arena) {
            attr[i].pValue = PORT_ArenaAlloc(arena, attr[i].ulValueLen);
            if (attr[i].pValue == NULL) {
                /* arena failures, just release the mark */
                PORT_ArenaRelease(arena, mark);
                PK11_ExitSlotMonitor(slot);
                return CKR_HOST_MEMORY;
            }
        } else {
            attr[i].pValue = PORT_Alloc(attr[i].ulValueLen);
            if (attr[i].pValue == NULL) {
                /* Separate malloc failures, loop to release what we have
                 * so far */

                int j;
                for (j = 0; j < i; j++) {
                    PORT_Free(attr[j].pValue);
                    /* don't give the caller pointers to freed memory */
                    attr[j].pValue = NULL;
                }
                PK11_ExitSlotMonitor(slot);
                return CKR_HOST_MEMORY;
            }
        }
    }

    /*
     * finally get the results.
     */

    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count);
    PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        if (arena) {
            PORT_ArenaRelease(arena, mark);
        } else {
            for (i = 0; i < count; i++) {
                PORT_Free(attr[i].pValue);
                /* don't give the caller pointers to freed memory */
                attr[i].pValue = NULL;
            }
        }
    } else if (arena && mark) {
        PORT_ArenaUnmark(arena, mark);
    }
    return crv;
}

PRBool
PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
{
    return (PRBool)PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE);
}

char *
PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
{
    char *nickname = NULL;
    SECItem result;
    SECStatus rv;

    rv = PK11_ReadAttribute(slot, id, CKA_LABEL, NULL, &result);
    if (rv != SECSuccess) {
        return NULL;
    }

    nickname = PORT_ZAlloc(result.len + 1);
    if (nickname == NULL) {
        PORT_Free(result.data);
        return NULL;
    }
    PORT_Memcpy(nickname, result.data, result.len);
    PORT_Free(result.data);
    return nickname;
}

SECStatus
PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
                       const char *nickname)
{
    int len = PORT_Strlen(nickname);
    CK_ATTRIBUTE setTemplate;
    CK_RV crv;
    CK_SESSION_HANDLE rwsession;

    if (len < 0) {
        return SECFailure;
    }

    PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *)nickname, len);
    rwsession = PK11_GetRWSession(slot);
    if (rwsession == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_BAD_DATA);
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
                                                 &setTemplate, 1);
    PK11_RestoreROSession(slot, rwsession);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

/*
 * strip leading zero's from key material
 */

void
pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib)
{
    char *ptr = (char *)attrib->pValue;
    unsigned long len = attrib->ulValueLen;

    while ((len > 1) && (*ptr == 0)) {
        len--;
        ptr++;
    }
    attrib->pValue = ptr;
    attrib->ulValueLen = len;
}

/*
 * get a new session on a slot. If we run out of session, use the slot's
 * 'exclusive' session. In this case owner becomes false.
 */

CK_SESSION_HANDLE
pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner)
{
    CK_SESSION_HANDLE session;
    *owner = PR_TRUE;
    if (!slot->isThreadSafe)
        PK11_EnterSlotMonitor(slot);
    if (PK11_GETTAB(slot)->C_OpenSession(slot->slotID, CKF_SERIAL_SESSION,
                                         slot, pk11_notify, &session) != CKR_OK) {
        *owner = PR_FALSE;
        session = slot->session;
    }
    if (!slot->isThreadSafe)
        PK11_ExitSlotMonitor(slot);

    return session;
}

void
pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE session, PRBool owner)
{
    if (!owner)
        return;
    if (!slot->isThreadSafe)
        PK11_EnterSlotMonitor(slot);
    (void)PK11_GETTAB(slot)->C_CloseSession(session);
    if (!slot->isThreadSafe)
        PK11_ExitSlotMonitor(slot);
}

SECStatus
PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
                     const CK_ATTRIBUTE *theTemplate, int count,
                     PRBool token, CK_OBJECT_HANDLE *objectID)
{
    CK_SESSION_HANDLE rwsession;
    CK_RV crv;
    SECStatus rv = SECSuccess;

    rwsession = session;
    if (token) {
        rwsession = PK11_GetRWSession(slot);
    } else if (rwsession == CK_INVALID_HANDLE) {
        rwsession = slot->session;
        if (rwsession != CK_INVALID_HANDLE)
            PK11_EnterSlotMonitor(slot);
    }
    if (rwsession == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_BAD_DATA);
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_CreateObject(rwsession,
                                            /* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate,
                                            count, objectID);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        rv = SECFailure;
    }
    if (token) {
        PK11_RestoreROSession(slot, rwsession);
    } else if (session == CK_INVALID_HANDLE) {
        PK11_ExitSlotMonitor(slot);
    }

    return rv;
}

/* This function may add a maximum of 9 attributes. */
unsigned int
pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue)
{

    const static CK_ATTRIBUTE_TYPE attrTypes[12] = {
        CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN,
        CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */,
        0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE
    };

    const CK_ATTRIBUTE_TYPE *pType = attrTypes;
    CK_ATTRIBUTE *attr = attrs;
    CK_FLAGS test = CKF_ENCRYPT;

    PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS));
    flags &= CKF_KEY_OPERATION_FLAGS;

    for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) {
        if (test & flags) {
            flags ^= test;
            PR_ASSERT(*pType);
            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
            ++attr;
        }
    }
    return (attr - attrs);
}

/*
 * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE
 * and PK11_ATTR_PUBLIC are set.
 */

PRBool
pk11_BadAttrFlags(PK11AttrFlags attrFlags)
{
    PK11AttrFlags trueFlags = attrFlags & 0x55555555;
    PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555;
    return ((trueFlags & falseFlags) != 0);
}

/*
 * This function may add a maximum of 5 attributes.
 * The caller must make sure the attribute flags don't have conflicts.
 */

unsigned int
pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs,
                           CK_BBOOL *ckTrue, CK_BBOOL *ckFalse)
{
    const static CK_ATTRIBUTE_TYPE attrTypes[5] = {
        CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE,
        CKA_EXTRACTABLE
    };

    const CK_ATTRIBUTE_TYPE *pType = attrTypes;
    CK_ATTRIBUTE *attr = attrs;
    PK11AttrFlags test = PK11_ATTR_TOKEN;

    PR_ASSERT(!pk11_BadAttrFlags(attrFlags));

    /* we test two related bitflags in each iteration */
    for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) {
        if (test & attrFlags) {
            attrFlags ^= test;
            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
            ++attr;
        } else if ((test << 1) & attrFlags) {
            attrFlags ^= (test << 1);
            PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse);
            ++attr;
        }
    }
    return (attr - attrs);
}

/*
 * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually
 * set up a signature to get the signaure length.
 */

static int
pk11_backupGetSignLength(SECKEYPrivateKey *key)
{
    PK11SlotInfo *slot = key->pkcs11Slot;
    CK_MECHANISM mech = { 0, NULL, 0 };
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    CK_ULONG len;
    CK_RV crv;
    unsigned char h_data[20] = { 0 };
    unsigned char buf[20]; /* obviously to small */
    CK_ULONG smallLen = sizeof(buf);

    mech.mechanism = PK11_MapSignKeyType(key->keyType);

    session = pk11_GetNewSession(slot, &owner);
    if (!owner || !(slot->isThreadSafe))
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID);
    if (crv != CKR_OK) {
        if (!owner || !(slot->isThreadSafe))
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        return -1;
    }
    len = 0;
    crv = PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data),
                                    NULL, &len);
    /* now call C_Sign with too small a buffer to clear the session state */
    (void)PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data), buf, &smallLen);

    if (!owner || !(slot->isThreadSafe))
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return -1;
    }
    return len;
}

/*
 * get the length of a signature object based on the key
 */

int
PK11_SignatureLen(SECKEYPrivateKey *key)
{
    int val;
    SECItem attributeItem = { siBuffer, NULL, 0 };
    SECStatus rv;
    int length;

    switch (key->keyType) {
        case rsaKey:
            val = PK11_GetPrivateModulusLen(key);
            if (val == -1) {
                return pk11_backupGetSignLength(key);
            }
            return (unsigned long)val;

        case fortezzaKey:
            return 40;

        case dsaKey:
            rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME,
                                    NULL, &attributeItem);
            if (rv == SECSuccess) {
                length = attributeItem.len;
                if ((length > 0) && attributeItem.data[0] == 0) {
                    length--;
                }
                PORT_Free(attributeItem.data);
                return length * 2;
            }
            return pk11_backupGetSignLength(key);
        case ecKey:
        case edKey:
            rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS,
                                    NULL, &attributeItem);
            if (rv == SECSuccess) {
                length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem);
                PORT_Free(attributeItem.data);
                if (length != 0) {
                    length = ((length + 7) / 8) * 2;
                    return length;
                }
            }
            return pk11_backupGetSignLength(key);
        default:
            break;
    }
    PORT_SetError(SEC_ERROR_INVALID_KEY);
    return 0;
}

/*
 * copy a key (or any other object) on a token
 */

CK_OBJECT_HANDLE
PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject)
{
    CK_OBJECT_HANDLE destObject;
    CK_RV crv;

    PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_CopyObject(slot->session, srcObject, NULL, 0,
                                          &destObject);
    PK11_ExitSlotMonitor(slot);
    if (crv == CKR_OK)
        return destObject;
    PORT_SetError(PK11_MapError(crv));
    return CK_INVALID_HANDLE;
}

PRBool
pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
                        CK_ATTRIBUTE_TYPE target)
{
    for (; numAttrs > 0; ++attr, --numAttrs) {
        if (attr->type == target)
            return PR_TRUE;
    }
    return PR_FALSE;
}

/*
 * Recover the Signed data. We need this because our old verify can't
 * figure out which hash algorithm to use until we decryptted this.
 */

SECStatus
PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig,
                   SECItem *dsig, void *wincx)
{
    PK11SlotInfo *slot = key->pkcs11Slot;
    CK_OBJECT_HANDLE id = key->pkcs11ID;
    CK_MECHANISM mech = { 0, NULL, 0 };
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    CK_ULONG len;
    CK_RV crv;

    mech.mechanism = PK11_MapSignKeyType(key->keyType);

    if (slot == NULL) {
        slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
                                              CKF_VERIFY_RECOVER, 0, wincx);
        if (slot == NULL) {
            PORT_SetError(SEC_ERROR_NO_MODULE);
            return SECFailure;
        }
        id = PK11_ImportPublicKey(slot, key, PR_FALSE);
    } else {
        PK11_ReferenceSlot(slot);
    }

    if (id == CK_INVALID_HANDLE) {
        PK11_FreeSlot(slot);
        PORT_SetError(SEC_ERROR_BAD_KEY);
        return SECFailure;
    }

    session = pk11_GetNewSession(slot, &owner);
    if (!owner || !(slot->isThreadSafe))
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session, &mech, id);
    if (crv != CKR_OK) {
        if (!owner || !(slot->isThreadSafe))
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        PK11_FreeSlot(slot);
        return SECFailure;
    }
    len = dsig->len;
    crv = PK11_GETTAB(slot)->C_VerifyRecover(session, sig->data,
                                             sig->len, dsig->data, &len);
    if (!owner || !(slot->isThreadSafe))
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    dsig->len = len;
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        PK11_FreeSlot(slot);
        return SECFailure;
    }
    PK11_FreeSlot(slot);
    return SECSuccess;
}

/*
 * verify a signature from its hash.
 */

SECStatus
PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash,
            void *wincx)
{
    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
    return PK11_VerifyWithMechanism(key, mech, NULL, sig, hash, wincx);
}

/*
 * Verify a signature from its hash using the given algorithm.
 */

SECStatus
PK11_VerifyWithMechanism(SECKEYPublicKey *key, CK_MECHANISM_TYPE mechanism,
                         const SECItem *param, const SECItem *sig,
                         const SECItem *hash, void *wincx)
{
    PK11SlotInfo *slot = key->pkcs11Slot;
    CK_OBJECT_HANDLE id = key->pkcs11ID;
    CK_MECHANISM mech = { 0, NULL, 0 };
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    CK_RV crv;

    mech.mechanism = mechanism;
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }

    if (slot == NULL) {
        unsigned int length = 0;
        if ((mech.mechanism == CKM_DSA) &&
            /* 129 is 1024 bits translated to bytes and
             * padded with an optional '0' to maintain a
             * positive sign */

            (key->u.dsa.params.prime.len > 129)) {
            /* we need to get a slot that not only can do DSA, but can do DSA2
             * key lengths */

            length = key->u.dsa.params.prime.len;
            if (key->u.dsa.params.prime.data[0] == 0) {
                length--;
            }
            /* convert keysize to bits for slot lookup */
            length *= 8;
        }
        slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
                                              CKF_VERIFY, length, wincx);
        if (slot == NULL) {
            PORT_SetError(SEC_ERROR_NO_MODULE);
            return SECFailure;
        }
        id = PK11_ImportPublicKey(slot, key, PR_FALSE);

    } else {
        PK11_ReferenceSlot(slot);
    }

    if (id == CK_INVALID_HANDLE) {
        PK11_FreeSlot(slot);
        PORT_SetError(SEC_ERROR_BAD_KEY);
        return SECFailure;
    }

    session = pk11_GetNewSession(slot, &owner);
    if (!owner || !(slot->isThreadSafe))
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_VerifyInit(session, &mech, id);
    if (crv != CKR_OK) {
        if (!owner || !(slot->isThreadSafe))
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PK11_FreeSlot(slot);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_Verify(session, hash->data,
                                      hash->len, sig->data, sig->len);
    if (!owner || !(slot->isThreadSafe))
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    PK11_FreeSlot(slot);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

/*
 * sign a hash. The algorithm is determined by the key.
 */

SECStatus
PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash)
{
    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
    return PK11_SignWithMechanism(key, mech, NULL, sig, hash);
}

/*
 * Sign a hash using the given algorithm.
 */

SECStatus
PK11_SignWithMechanism(SECKEYPrivateKey *key, CK_MECHANISM_TYPE mechanism,
                       const SECItem *param, SECItem *sig, const SECItem *hash)
{
    PK11SlotInfo *slot = key->pkcs11Slot;
    CK_MECHANISM mech = { 0, NULL, 0 };
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    PRBool haslock = PR_FALSE;
    CK_ULONG len;
    CK_RV crv;

    mech.mechanism = mechanism;
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }

    if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) {
        PK11_HandlePasswordCheck(slot, key->wincx);
    }

    session = pk11_GetNewSession(slot, &owner);
    haslock = (!owner || !(slot->isThreadSafe));
    if (haslock)
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID);
    if (crv != CKR_OK) {
        if (haslock)
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }

    /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
     * do C_Login with CKU_CONTEXT_SPECIFIC
     * between C_SignInit and C_Sign */

    if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
        PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
    }

    len = sig->len;
    crv = PK11_GETTAB(slot)->C_Sign(session, hash->data,
                                    hash->len, sig->data, &len);
    if (haslock)
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    sig->len = len;
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

/*
 * sign data with a MAC key.
 */

SECStatus
PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism,
                    SECItem *param, SECItem *sig, const SECItem *data)
{
    PK11SlotInfo *slot = symKey->slot;
    CK_MECHANISM mech = { 0, NULL, 0 };
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    PRBool haslock = PR_FALSE;
    CK_ULONG len;
    CK_RV crv;

    mech.mechanism = mechanism;
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }

    session = pk11_GetNewSession(slot, &owner);
    haslock = (!owner || !(slot->isThreadSafe));
    if (haslock)
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, symKey->objectID);
    if (crv != CKR_OK) {
        if (haslock)
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }

    len = sig->len;
    crv = PK11_GETTAB(slot)->C_Sign(session, data->data,
                                    data->len, sig->data, &len);
    if (haslock)
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    sig->len = len;
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

SECStatus
PK11_Decrypt(PK11SymKey *symKey,
             CK_MECHANISM_TYPE mechanism, SECItem *param,
             unsigned char *out, unsigned int *outLen,
             unsigned int maxLen,
             const unsigned char *enc, unsigned encLen)
{
    PK11SlotInfo *slot = symKey->slot;
    CK_MECHANISM mech = { 0, NULL, 0 };
    CK_ULONG len = maxLen;
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    PRBool haslock = PR_FALSE;
    CK_RV crv;

    mech.mechanism = mechanism;
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }

    session = pk11_GetNewSession(slot, &owner);
    haslock = (!owner || !slot->isThreadSafe);
    if (haslock)
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID);
    if (crv != CKR_OK) {
        if (haslock)
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }

    crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
                                       out, &len);
    if (haslock)
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    *outLen = len;
    return SECSuccess;
}

SECStatus
PK11_Encrypt(PK11SymKey *symKey,
             CK_MECHANISM_TYPE mechanism, SECItem *param,
             unsigned char *out, unsigned int *outLen,
             unsigned int maxLen,
             const unsigned char *data, unsigned int dataLen)
{
    PK11SlotInfo *slot = symKey->slot;
    CK_MECHANISM mech = { 0, NULL, 0 };
    CK_ULONG len = maxLen;
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    PRBool haslock = PR_FALSE;
    CK_RV crv;

    mech.mechanism = mechanism;
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }

    session = pk11_GetNewSession(slot, &owner);
    haslock = (!owner || !slot->isThreadSafe);
    if (haslock)
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID);
    if (crv != CKR_OK) {
        if (haslock)
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data,
                                       dataLen, out, &len);
    if (haslock)
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    *outLen = len;
    return SECSuccess;
}

static SECStatus
pk11_PrivDecryptRaw(SECKEYPrivateKey *key,
                    unsigned char *data, unsigned *outLen, unsigned int maxLen,
                    const unsigned char *enc, unsigned encLen,
                    CK_MECHANISM_PTR mech)
{
    PK11SlotInfo *slot = key->pkcs11Slot;
    CK_ULONG out = maxLen;
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    PRBool haslock = PR_FALSE;
    CK_RV crv;

    if (key->keyType != rsaKey) {
        PORT_SetError(SEC_ERROR_INVALID_KEY);
        return SECFailure;
    }

    /* Why do we do a PK11_handle check here? for simple
     * decryption? .. because the user may have asked for 'ask always'
     * and this is a private key operation. In practice, thought, it's mute
     * since only servers wind up using this function */

    if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) {
        PK11_HandlePasswordCheck(slot, key->wincx);
    }
    session = pk11_GetNewSession(slot, &owner);
    haslock = (!owner || !(slot->isThreadSafe));
    if (haslock)
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID);
    if (crv != CKR_OK) {
        if (haslock)
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }

    /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
     * do C_Login with CKU_CONTEXT_SPECIFIC
     * between C_DecryptInit and C_Decrypt
     * ... But see note above about servers */

    if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
        PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
    }

    crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
                                       data, &out);
    if (haslock)
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    *outLen = out;
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

SECStatus
PK11_PubDecryptRaw(SECKEYPrivateKey *key,
                   unsigned char *data, unsigned *outLen, unsigned int maxLen,
                   const unsigned char *enc, unsigned encLen)
{
    CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 };
    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
}

SECStatus
PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key,
                      unsigned char *data, unsigned *outLen, unsigned int maxLen,
                      const unsigned char *enc, unsigned encLen)
{
    CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 };
    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
}

static SECStatus
pk11_PubEncryptRaw(SECKEYPublicKey *key,
                   unsigned char *out, unsigned int *outLen,
                   unsigned int maxLen,
                   const unsigned char *data, unsigned dataLen,
                   CK_MECHANISM_PTR mech, void *wincx)
{
    PK11SlotInfo *slot;
    CK_OBJECT_HANDLE id;
    CK_ULONG len = maxLen;
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    CK_RV crv;

    slot = PK11_GetBestSlotWithAttributes(mech->mechanism, CKF_ENCRYPT, 0, wincx);
    if (slot == NULL) {
        PORT_SetError(SEC_ERROR_NO_MODULE);
        return SECFailure;
    }

    id = PK11_ImportPublicKey(slot, key, PR_FALSE);

    if (id == CK_INVALID_HANDLE) {
        PK11_FreeSlot(slot);
        PORT_SetError(SEC_ERROR_BAD_KEY);
        return SECFailure;
    }

    session = pk11_GetNewSession(slot, &owner);
    if (!owner || !(slot->isThreadSafe))
        PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id);
    if (crv != CKR_OK) {
        if (!owner || !(slot->isThreadSafe))
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PK11_FreeSlot(slot);
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, dataLen,
                                       out, &len);
    if (!owner || !(slot->isThreadSafe))
        PK11_ExitSlotMonitor(slot);
    pk11_CloseSession(slot, session, owner);
    PK11_FreeSlot(slot);
    *outLen = len;
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

SECStatus
PK11_PubEncryptRaw(SECKEYPublicKey *key,
                   unsigned char *enc,
                   const unsigned char *data, unsigned dataLen,
                   void *wincx)
{
    CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 };
    unsigned int outLen;
    if (!key || key->keyType != rsaKey) {
        PORT_SetError(SEC_ERROR_BAD_KEY);
        return SECFailure;
    }
    outLen = SECKEY_PublicKeyStrength(key);
    return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
                              wincx);
}

SECStatus
PK11_PubEncryptPKCS1(SECKEYPublicKey *key,
                     unsigned char *enc,
                     const unsigned char *data, unsigned dataLen,
                     void *wincx)
{
    CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 };
    unsigned int outLen;
    if (!key || key->keyType != rsaKey) {
        PORT_SetError(SEC_ERROR_BAD_KEY);
        return SECFailure;
    }
    outLen = SECKEY_PublicKeyStrength(key);
    return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
                              wincx);
}

SECStatus
PK11_PrivDecrypt(SECKEYPrivateKey *key,
                 CK_MECHANISM_TYPE mechanism, SECItem *param,
                 unsigned char *out, unsigned int *outLen,
                 unsigned int maxLen,
                 const unsigned char *enc, unsigned encLen)
{
    CK_MECHANISM mech = { mechanism, NULL, 0 };
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }
    return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech);
}

SECStatus
PK11_PubEncrypt(SECKEYPublicKey *key,
                CK_MECHANISM_TYPE mechanism, SECItem *param,
                unsigned char *out, unsigned int *outLen,
                unsigned int maxLen,
                const unsigned char *data, unsigned dataLen,
                void *wincx)
{
    CK_MECHANISM mech = { mechanism, NULL, 0 };
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    }
    return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech,
                              wincx);
}

SECKEYPrivateKey *
PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
                   CK_MECHANISM_TYPE wrapType, SECItem *param,
                   SECItem *wrappedKey, SECItem *label,
                   SECItem *idValue, PRBool perm, PRBool sensitive,
                   CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage,
                   int usageCount, void *wincx)
{
    CK_BBOOL cktrue = CK_TRUE;
    CK_BBOOL ckfalse = CK_FALSE;
    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
    CK_ATTRIBUTE keyTemplate[15];
    int templateCount = 0;
    CK_OBJECT_HANDLE privKeyID;
    CK_MECHANISM mechanism;
    CK_ATTRIBUTE *attrs = keyTemplate;
    SECItem *param_free = NULL, *ck_id = NULL;
    CK_RV crv;
    CK_SESSION_HANDLE rwsession;
    PK11SymKey *newKey = NULL;
    int i;

    if (!slot || !wrappedKey || !idValue) {
        /* SET AN ERROR!!! */
        return NULL;
    }

    ck_id = PK11_MakeIDFromPubKey(idValue);
    if (!ck_id) {
        return NULL;
    }

    PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse,
                  sizeof(cktrue));
    attrs++;
    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
    attrs++;
    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
    attrs++;
    PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse,
                  sizeof(cktrue));
    attrs++;
    PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse,
                  sizeof(cktrue));
    attrs++;
    if (label && label->data) {
        PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len);
        attrs++;
    }
    PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
    attrs++;
    for (i = 0; i < usageCount; i++) {
        PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue));
        attrs++;
    }

    if (PK11_IsInternal(slot)) {
        PK11_SETATTRS(attrs, CKA_NSS_DB, idValue->data,
                      idValue->len);
        attrs++;
    }

    templateCount = attrs - keyTemplate;
    PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)));

    mechanism.mechanism = wrapType;
    if (!param)
        param = param_free = PK11_ParamFromIV(wrapType, NULL);
    if (param) {
        mechanism.pParameter = param->data;
        mechanism.ulParameterLen = param->len;
    } else {
        mechanism.pParameter = NULL;
        mechanism.ulParameterLen = 0;
    }

    if (wrappingKey->slot != slot) {
        newKey = pk11_CopyToSlot(slot, wrapType, CKA_UNWRAP, wrappingKey);
    } else {
        newKey = PK11_ReferenceSymKey(wrappingKey);
    }

    if (newKey) {
        if (perm) {
            /* Get RW Session will either lock the monitor if necessary,
             *  or return a thread safe session handle, or fail. */

            rwsession = PK11_GetRWSession(slot);
        } else {
            rwsession = slot->session;
            if (rwsession != CK_INVALID_HANDLE)
                PK11_EnterSlotMonitor(slot);
        }
        /* This is a lot a work to deal with fussy PKCS #11 modules
         * that can't bother to return BAD_DATA when presented with an
         * invalid session! */

        if (rwsession == CK_INVALID_HANDLE) {
            PORT_SetError(SEC_ERROR_BAD_DATA);
            goto loser;
        }
        crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism,
                                             newKey->objectID,
                                             wrappedKey->data,
                                             wrappedKey->len, keyTemplate,
                                             templateCount, &privKeyID);

        if (perm) {
            PK11_RestoreROSession(slot, rwsession);
        } else {
            PK11_ExitSlotMonitor(slot);
        }
        PK11_FreeSymKey(newKey);
        newKey = NULL;
    } else {
        crv = CKR_FUNCTION_NOT_SUPPORTED;
    }

    SECITEM_FreeItem(ck_id, PR_TRUE);
    ck_id = NULL;

    if (crv != CKR_OK) {
        /* we couldn't unwrap the key, use the internal module to do the
         * unwrap, then load the new key into the token */

        PK11SlotInfo *int_slot = PK11_GetInternalSlot();

        if (int_slot && (slot != int_slot)) {
            SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
                                                           wrappingKey, wrapType, param, wrappedKey, label,
                                                           idValue, PR_FALSE, PR_FALSE,
                                                           keyType, usage, usageCount, wincx);
            if (privKey) {
                SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot, privKey,
                                                                NULL, perm, sensitive);
                SECKEY_DestroyPrivateKey(privKey);
                PK11_FreeSlot(int_slot);
                SECITEM_FreeItem(param_free, PR_TRUE);
                return newPrivKey;
            }
        }
        if (int_slot)
            PK11_FreeSlot(int_slot);
        PORT_SetError(PK11_MapError(crv));
        SECITEM_FreeItem(param_free, PR_TRUE);
        return NULL;
    }
    SECITEM_FreeItem(param_free, PR_TRUE);
    return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx);

loser:
    PK11_FreeSymKey(newKey);
    SECITEM_FreeItem(ck_id, PR_TRUE);
    SECITEM_FreeItem(param_free, PR_TRUE);
    return NULL;
}

/*
 * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey
 * The strategy is to get both keys to reside in the same slot,
 * one that can perform the desired crypto mechanism and then
 * call C_WrapKey after all the setup has taken place.
 */

SECStatus
PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
                 SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType,
                 SECItem *param, SECItem *wrappedKey, void *wincx)
{
    PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where
                                                   * the private key
                                                   * we are going to
                                                   * wrap lives.
                                                   */

    PK11SymKey *newSymKey = NULL;
    SECKEYPrivateKey *newPrivKey = NULL;
    SECItem *param_free = NULL;
    CK_ULONG len = wrappedKey->len;
    CK_MECHANISM mech;
    CK_RV crv;

    if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) {
        /* Figure out a slot that does the mechanism and try to import
         * the private key onto that slot.
         */

        PK11SlotInfo *int_slot = PK11_GetInternalSlot();

        privSlot = int_slot; /* The private key has a new home */
        newPrivKey = PK11_LoadPrivKey(privSlot, privKey, NULL, PR_FALSE, PR_FALSE);
        /* newPrivKey has allocated its own reference to the slot, so it's
         * safe until we destroy newPrivkey.
         */

        PK11_FreeSlot(int_slot);
        if (newPrivKey == NULL) {
            return SECFailure;
        }
        privKey = newPrivKey;
    }

    if (privSlot != wrappingKey->slot) {
        newSymKey = pk11_CopyToSlot(privSlot, wrapType, CKA_WRAP,
                                    wrappingKey);
        wrappingKey = newSymKey;
    }

    if (wrappingKey == NULL) {
        if (newPrivKey) {
            SECKEY_DestroyPrivateKey(newPrivKey);
        }
        return SECFailure;
    }
    mech.mechanism = wrapType;
    if (!param) {
        param = param_free = PK11_ParamFromIV(wrapType, NULL);
    }
    if (param) {
        mech.pParameter = param->data;
        mech.ulParameterLen = param->len;
    } else {
        mech.pParameter = NULL;
        mech.ulParameterLen = 0;
    }

    PK11_EnterSlotMonitor(privSlot);
    crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech,
                                           wrappingKey->objectID,
                                           privKey->pkcs11ID,
                                           wrappedKey->data, &len);
    PK11_ExitSlotMonitor(privSlot);

    if (newSymKey) {
        PK11_FreeSymKey(newSymKey);
    }
    if (newPrivKey) {
        SECKEY_DestroyPrivateKey(newPrivKey);
    }
    if (param_free) {
        SECITEM_FreeItem(param_free, PR_TRUE);
    }

    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }

    wrappedKey->len = len;
    return SECSuccess;
}

#if 0
/*
 * Sample code relating to linked list returned by PK11_FindGenericObjects
 */


/*
 * You can walk the list with the following code:
 */

    firstObj = PK11_FindGenericObjects(slot, objClass);
    for (thisObj=firstObj;
         thisObj;
         thisObj=PK11_GetNextGenericObject(thisObj)) {
        /* operate on thisObj */
    }
/*
 * If you want a particular object from the list...
 */

    firstObj = PK11_FindGenericObjects(slot, objClass);
    for (thisObj=firstObj;
         thisObj;
         thisObj=PK11_GetNextGenericObject(thisObj)) {
      if (isMyObj(thisObj)) {
       if ( thisObj == firstObj) {
                /* NOTE: firstObj could be NULL at this point */
      firstObj = PK11_GetNextGenericObject(thsObj);
       }
       PK11_UnlinkGenericObject(thisObj);
            myObj = thisObj;
            break;
        }
    }

    PK11_DestroyGenericObjects(firstObj);

      /* use myObj */

    PK11_DestroyGenericObject(myObj);
#endif /* sample code */

/*
 * return a linked, non-circular list of generic objects.
 * If you are only interested
 * in one object, just use the first object in the list. To find the
 * rest of the list use PK11_GetNextGenericObject() to return the next object.
 */

PK11GenericObject *
PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass)
{
    CK_ATTRIBUTE template[1];
    CK_ATTRIBUTE *attrs = template;
    CK_OBJECT_HANDLE *objectIDs = NULL;
    PK11GenericObject *lastObj = NULL, *obj;
    PK11GenericObject *firstObj = NULL;
    int i, count = 0;

    PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass));
    attrs++;

    objectIDs = pk11_FindObjectsByTemplate(slot, template, 1, &count);
    if (objectIDs == NULL) {
        return NULL;
    }

    /* where we connect our object once we've created it.. */
    for (i = 0; i < count; i++) {
        obj = PORT_New(PK11GenericObject);
        if (!obj) {
            if (firstObj) {
                PK11_DestroyGenericObjects(firstObj);
            }
            PORT_Free(objectIDs);
            return NULL;
        }
        /* initialize it */
        obj->slot = PK11_ReferenceSlot(slot);
        obj->objectID = objectIDs[i];
        obj->owner = PR_FALSE;
        obj->next = NULL;
        obj->prev = NULL;

        /* link it in */
        if (firstObj == NULL) {
            firstObj = obj;
        } else {
            PK11_LinkGenericObject(lastObj, obj);
        }
        lastObj = obj;
    }
    PORT_Free(objectIDs);
    return firstObj;
}

/*
 * get the Next Object in the list.
 */

PK11GenericObject *
PK11_GetNextGenericObject(PK11GenericObject *object)
{
    return object->next;
}

PK11GenericObject *
PK11_GetPrevGenericObject(PK11GenericObject *object)
{
    return object->prev;
}

/*
 * Link a single object into a new list.
 * if the object is already in another list, remove it first.
 */

SECStatus
PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object)
{
    PK11_UnlinkGenericObject(object);
    object->prev = list;
    object->next = list->next;
    list->next = object;
    if (object->next != NULL) {
        object->next->prev = object;
    }
    return SECSuccess;
}

/*
 * remove an object from the list. If the object isn't already in
 * a list unlink becomes a noop.
 */

SECStatus
PK11_UnlinkGenericObject(PK11GenericObject *object)
{
    if (object->prev != NULL) {
        object->prev->next = object->next;
    }
    if (object->next != NULL) {
        object->next->prev = object->prev;
    }

    object->next = NULL;
    object->prev = NULL;
    return SECSuccess;
}

/*
 * This function removes a single object from the list and destroys it.
 * For an already unlinked object there is no difference between
 * PK11_DestroyGenericObject and PK11_DestroyGenericObjects
 */

SECStatus
PK11_DestroyGenericObject(PK11GenericObject *object)
{
    if (object == NULL) {
        return SECSuccess;
    }

    PK11_UnlinkGenericObject(object);
    if (object->slot) {
        if (object->owner) {
            PK11_DestroyObject(object->slot, object->objectID);
        }
        PK11_FreeSlot(object->slot);
    }
    PORT_Free(object);
    return SECSuccess;
}

/*
 * walk down a link list of generic objects destroying them.
 * This will destroy all objects in a list that the object is linked into.
 * (the list is traversed in both directions).
 */

SECStatus
PK11_DestroyGenericObjects(PK11GenericObject *objects)
{
    PK11GenericObject *nextObject;
    PK11GenericObject *prevObject;

    if (objects == NULL) {
        return SECSuccess;
    }

    nextObject = objects->next;
    prevObject = objects->prev;

    /* delete all the objects after it in the list */
    for (; objects; objects = nextObject) {
        nextObject = objects->next;
        PK11_DestroyGenericObject(objects);
    }
    /* delete all the objects before it in the list */
    for (objects = prevObject; objects; objects = prevObject) {
        prevObject = objects->prev;
        PK11_DestroyGenericObject(objects);
    }
    return SECSuccess;
}

/*
 * Hand Create a new object and return the Generic object for our new object.
 */

PK11GenericObject *
pk11_CreateGenericObjectHelper(PK11SlotInfo *slot,
                               const CK_ATTRIBUTE *pTemplate,
                               int count, PRBool token, PRBool owner)
{
    CK_OBJECT_HANDLE objectID;
    PK11GenericObject *obj;
    CK_RV crv;

    PK11_EnterSlotMonitor(slot);
    crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count,
                               token, &objectID);
    PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return NULL;
    }

    obj = PORT_New(PK11GenericObject);
    if (!obj) {
        /* error set by PORT_New */
        return NULL;
    }

    /* initialize it */
    obj->slot = PK11_ReferenceSlot(slot);
    obj->objectID = objectID;
    obj->owner = owner;
    obj->next = NULL;
    obj->prev = NULL;
    return obj;
}

/* This is the classic interface. Applications would call this function to
 * create new object that would not be destroyed later. This lead to resource
 * leaks (and thus memory leaks in the PKCS #11 module).  To solve this we have
 * a new interface that automatically marks objects created on the fly to be
 * destroyed later.
 * The old interface is preserved because applications like Mozilla purposefully
 * leak the reference to be found later with PK11_FindGenericObjects. New
 * applications should use the new interface PK11_CreateManagedGenericObject */

PK11GenericObject *
PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate,
                         int count, PRBool token)
{
    return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
                                          PR_FALSE);
}

/* Use this interface. It will automatically destroy any temporary objects
 * (token = PR_FALSE) when the PK11GenericObject is freed. Permanent objects still
 * need to be destroyed by hand with PK11_DestroyTokenObject.
 */

PK11GenericObject *
PK11_CreateManagedGenericObject(PK11SlotInfo *slot,
                                const CK_ATTRIBUTE *pTemplate, int count, PRBool token)
{
    return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
                                          !token);
}

CK_OBJECT_HANDLE
PK11_GetObjectHandle(PK11ObjectType objType, void *objSpec,
                     PK11SlotInfo **slotp)
{
    CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE;
    PK11SlotInfo *slot = NULL;

    switch (objType) {
        case PK11_TypeGeneric:
            slot = ((PK11GenericObject *)objSpec)->slot;
            handle = ((PK11GenericObject *)objSpec)->objectID;
            break;
        case PK11_TypePrivKey:
            slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
            handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
            break;
        case PK11_TypePubKey:
            slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
            handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
            break;
        case PK11_TypeSymKey:
            slot = ((PK11SymKey *)objSpec)->slot;
            handle = ((PK11SymKey *)objSpec)->objectID;
            break;
        case PK11_TypeCert:
            handle = PK11_FindObjectForCert((CERTCertificate *)objSpec, NULL,
                                            &slot);
            break;
        default:
            PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
            break;
    }
    if (slotp) {
        *slotp = slot;
    }
    /* paranoia. If the object doesn't have a slot, then it's handle isn't
     * valid either */

    if (slot == NULL) {
        handle = CK_INVALID_HANDLE;
    }
    return handle;
}

/*
 * Change an attribute on a raw object
 */

SECStatus
PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec,
                       CK_ATTRIBUTE_TYPE attrType, SECItem *item)
{
    PK11SlotInfo *slot = NULL;
    CK_OBJECT_HANDLE handle = 0;
    CK_ATTRIBUTE setTemplate;
    CK_RV crv;
    CK_SESSION_HANDLE rwsession;

    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
    if (handle == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
        return SECFailure;
    }

    PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *)item->data, item->len);
    rwsession = PK11_GetRWSession(slot);
    if (rwsession == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_BAD_DATA);
        return SECFailure;
    }
    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle,
                                                 &setTemplate, 1);
    PK11_RestoreROSession(slot, rwsession);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

SECStatus
PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec,
                      CK_ATTRIBUTE_TYPE attrType, SECItem *item)
{
    PK11SlotInfo *slot = NULL;
    CK_OBJECT_HANDLE handle = 0;

    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
    if (handle == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
        return SECFailure;
    }

    return PK11_ReadAttribute(slot, handle, attrType, NULL, item);
}

SECStatus
PK11_ReadRawAttributes(PLArenaPool *arena, PK11ObjectType objType, void *objSpec,
                       CK_ATTRIBUTE *pTemplate, unsigned int count)
{
    PK11SlotInfo *slot = NULL;
    CK_OBJECT_HANDLE handle = 0;

    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
    if (handle == CK_INVALID_HANDLE) {
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
        return SECFailure;
    }
    CK_RV crv = PK11_GetAttributes(arena, slot, handle, pTemplate, count);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }
    return SECSuccess;
}

SECStatus
PK11_ReadDistrustAfterAttribute(PK11SlotInfo *slot,
                                CK_OBJECT_HANDLE object,
                                CK_ATTRIBUTE_TYPE type,
                                /* out */ PRBool *distrusted,
                                /* out */ PRTime *time)
{
    if (!slot || !distrusted || !time) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    if (type != CKA_NSS_SERVER_DISTRUST_AFTER && type != CKA_NSS_EMAIL_DISTRUST_AFTER) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    // The CKA_NSS_SERVER_DISTRUST_AFTER and CKA_NSS_EMAIL_DISTRUST_AFTER
    // attributes have either a 13 byte UTCTime value or a 1 byte value
    // (equal to 0) indicating that no distrust after date is set.
    unsigned char buf[13] = { 0 };
    CK_ATTRIBUTE attr = { .type = type, .pValue = buf, .ulValueLen = sizeof buf };
    CK_RV crv;

    PK11_EnterSlotMonitor(slot);
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, object, &attr, 1);
    PK11_ExitSlotMonitor(slot);
    if (crv != CKR_OK) {
        PORT_SetError(PK11_MapError(crv));
        return SECFailure;
    }

    if (attr.ulValueLen == 1 && buf[0] == 0) {
        // The distrust after date is not set.
        *distrusted = PR_FALSE;
        return SECSuccess;
    }

    if (attr.ulValueLen != sizeof buf) {
        // Ensure the date is encoded in the expected 13 byte format.
        PORT_SetError(SEC_ERROR_INVALID_TIME);
        return SECFailure;
    }

    *distrusted = PR_TRUE;
    SECItem item = { siUTCTime, buf, sizeof buf };
    return DER_UTCTimeToTime(time, &item);
}

/*
 * return the object handle that matches the template
 */

CK_OBJECT_HANDLE
pk11_FindObjectByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *theTemplate, size_t tsize)
{
    CK_OBJECT_HANDLE object;
    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
    CK_ULONG objectCount;

    /*
     * issue the find
     */

    PK11_EnterSlotMonitor(slot);
    if (slot->session != CK_INVALID_HANDLE) {
        crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
                                                   theTemplate, tsize);
    }
    if (crv != CKR_OK) {
        PK11_ExitSlotMonitor(slot);
        PORT_SetError(PK11_MapError(crv));
        return CK_INVALID_HANDLE;
    }

    crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, &object, 1, &objectCount);
    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
    PK11_ExitSlotMonitor(slot);
    if ((crv != CKR_OK) || (objectCount < 1)) {
        /* shouldn't use SSL_ERROR... here */
        PORT_SetError(crv != CKR_OK ? PK11_MapError(crv) : SSL_ERROR_NO_CERTIFICATE);
        return CK_INVALID_HANDLE;
    }

    /* blow up if the PKCS #11 module returns us and invalid object handle */
    PORT_Assert(object != CK_INVALID_HANDLE);
    return object;
}

/*
 * return all the object handles that matches the template
 */

CK_OBJECT_HANDLE *
pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
                           size_t templCount, int *object_count)
{
    CK_OBJECT_HANDLE *objID = NULL;
    CK_ULONG returned_count = 0;
    PRBool owner = PR_TRUE;
    CK_SESSION_HANDLE session;
    PRBool haslock = PR_FALSE;
    CK_RV crv = CKR_SESSION_HANDLE_INVALID;

    session = pk11_GetNewSession(slot, &owner);
    haslock = (!owner || !(slot->isThreadSafe));
    if (haslock) {
        PK11_EnterSlotMonitor(slot);
    }
    if (session != CK_INVALID_HANDLE) {
        crv = PK11_GETTAB(slot)->C_FindObjectsInit(session,
                                                   findTemplate, templCount);
    }
    if (crv != CKR_OK) {
        if (haslock)
            PK11_ExitSlotMonitor(slot);
        pk11_CloseSession(slot, session, owner);
        PORT_SetError(PK11_MapError(crv));
        *object_count = -1;
        return NULL;
    }

    /*
     * collect all the Matching Objects
     */

    do {
        CK_OBJECT_HANDLE *oldObjID = objID;

        if (objID == NULL) {
            objID = (CK_OBJECT_HANDLE *)PORT_Alloc(sizeof(CK_OBJECT_HANDLE) *
                                                   (*object_count + PK11_SEARCH_CHUNKSIZE));
        } else {
            objID = (CK_OBJECT_HANDLE *)PORT_Realloc(objID,
                                                     sizeof(CK_OBJECT_HANDLE) * (*object_count + PK11_SEARCH_CHUNKSIZE));
        }

        if (objID == NULL) {
            if (oldObjID)
                PORT_Free(oldObjID);
            break;
        }
        crv = PK11_GETTAB(slot)->C_FindObjects(session,
                                               &objID[*object_count], PK11_SEARCH_CHUNKSIZE, &returned_count);
        if (crv != CKR_OK) {
            PORT_SetError(PK11_MapError(crv));
            PORT_Free(objID);
            objID = NULL;
            break;
        }
        *object_count += returned_count;
    } while (returned_count == PK11_SEARCH_CHUNKSIZE);

    PK11_GETTAB(slot)->C_FindObjectsFinal(session);
    if (haslock) {
        PK11_ExitSlotMonitor(slot);
    }
    pk11_CloseSession(slot, session, owner);

    if (objID && (*object_count == 0)) {
        PORT_Free(objID);
        return NULL;
    }
    if (objID == NULL)
        *object_count = -1;
    return objID;
}

SECStatus
PK11_FindRawCertsWithSubject(PK11SlotInfo *slot, SECItem *derSubject,
                             CERTCertificateList **results)
{
    if (!slot || !derSubject || !results) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }
    *results = NULL;

    // derSubject->data may be null. If so, derSubject->len must be 0.
    if (!derSubject->data && derSubject->len != 0) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509;
    CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
    CK_ATTRIBUTE subjectTemplate[] = {
        { CKA_CERTIFICATE_TYPE, &ckc_x_509, sizeof(ckc_x_509) },
        { CKA_CLASS, &cko_certificate, sizeof(cko_certificate) },
        { CKA_SUBJECT, derSubject->data, derSubject->len },
    };
    const size_t templateCount = sizeof(subjectTemplate) / sizeof(subjectTemplate[0]);
    int handleCount = 0;
    CK_OBJECT_HANDLE *handles =
        pk11_FindObjectsByTemplate(slot, subjectTemplate, templateCount,
                                   &handleCount);
    if (!handles) {
        // pk11_FindObjectsByTemplate indicates there was an error by setting
        // handleCount to -1 (and it has set an error with PORT_SetError).
        if (handleCount == -1) {
            return SECFailure;
        }
        return SECSuccess;
    }
    PORT_Assert(handleCount > 0);
    if (handleCount <= 0) {
        PORT_Free(handles);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (handleCount > INT_MAX / sizeof(SECItem)) {
        PORT_Free(handles);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena) {
        PORT_Free(handles);
        return SECFailure;
    }
    CERTCertificateList *rawCertificates =
        PORT_ArenaNew(arena, CERTCertificateList);
    if (!rawCertificates) {
        PORT_Free(handles);
        PORT_FreeArena(arena, PR_FALSE);
        return SECFailure;
    }
    rawCertificates->arena = arena;
    rawCertificates->certs = PORT_ArenaNewArray(arena, SECItem, handleCount);
    if (!rawCertificates->certs) {
        PORT_Free(handles);
        PORT_FreeArena(arena, PR_FALSE);
        return SECFailure;
    }
    rawCertificates->len = handleCount;
    int handleIndex;
    for (handleIndex = 0; handleIndex < handleCount; handleIndex++) {
        SECStatus rv =
            PK11_ReadAttribute(slot, handles[handleIndex], CKA_VALUE, arena,
                               &rawCertificates->certs[handleIndex]);
        if (rv != SECSuccess) {
            PORT_Free(handles);
            PORT_FreeArena(arena, PR_FALSE);
            return SECFailure;
        }
        if (!rawCertificates->certs[handleIndex].data) {
            PORT_Free(handles);
            PORT_FreeArena(arena, PR_FALSE);
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
            return SECFailure;
        }
    }
    PORT_Free(handles);
    *results = rawCertificates;
    return SECSuccess;
}

/*
 * given a PKCS #11 object, match it's peer based on the KeyID. searchID
 * is typically a privateKey or a certificate while the peer is the opposite
 */

CK_OBJECT_HANDLE
PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,
               CK_OBJECT_CLASS matchclass)
{
    CK_ATTRIBUTE theTemplate[] = {
        { CKA_ID, NULL, 0 },
        { CKA_CLASS, NULL, 0 }
    };
    /* if you change the array, change the variable below as well */
    CK_ATTRIBUTE *keyclass = &theTemplate[1];
    const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
    /* if you change the array, change the variable below as well */
    CK_OBJECT_HANDLE peerID;
    PORTCheapArenaPool tmpArena;
    CK_RV crv;

    /* now we need to create space for the public key */
    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);

    crv = PK11_GetAttributes(&tmpArena.arena, slot, searchID, theTemplate, tsize);
    if (crv != CKR_OK) {
        PORT_DestroyCheapArena(&tmpArena);
        PORT_SetError(PK11_MapError(crv));
        return CK_INVALID_HANDLE;
    }

    if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
        PORT_DestroyCheapArena(&tmpArena);
        if (matchclass == CKO_CERTIFICATE)
            PORT_SetError(SEC_ERROR_BAD_KEY);
        else
            PORT_SetError(SEC_ERROR_NO_KEY);
        return CK_INVALID_HANDLE;
    }

    /*
     * issue the find
     */

    *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;

    peerID = pk11_FindObjectByTemplate(slot, theTemplate, tsize);
    PORT_DestroyCheapArena(&tmpArena);

    return peerID;
}

/*
 * count the number of objects that match the template.
 */

int
PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
                      int templCount)
{
    CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE];
    int object_count = 0;
    CK_ULONG returned_count = 0;
    CK_RV crv = CKR_SESSION_HANDLE_INVALID;

    PK11_EnterSlotMonitor(slot);
    if (slot->session != CK_INVALID_HANDLE) {
        crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
                                                   findTemplate, templCount);
    }
    if (crv != CKR_OK) {
        PK11_ExitSlotMonitor(slot);
        PORT_SetError(PK11_MapError(crv));
        return object_count;
    }

    /*
     * collect all the Matching Objects
     */

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

--> maximum size reached

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

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.11 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.