tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11obj.c (74635B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * This file manages object type indepentent functions.
      6 */
      7 #include <limits.h>
      8 #include <stddef.h>
      9 
     10 #include "seccomon.h"
     11 #include "secder.h"
     12 #include "secmod.h"
     13 #include "secmodi.h"
     14 #include "secmodti.h"
     15 #include "pkcs11.h"
     16 #include "pkcs11t.h"
     17 #include "pk11func.h"
     18 #include "keyhi.h"
     19 #include "keyi.h"
     20 #include "secitem.h"
     21 #include "secerr.h"
     22 #include "sslerr.h"
     23 
     24 #define PK11_SEARCH_CHUNKSIZE 10
     25 
     26 /*
     27 * Build a block big enough to hold the data
     28 */
     29 SECItem *
     30 PK11_BlockData(SECItem *data, unsigned long size)
     31 {
     32    SECItem *newData;
     33 
     34    if (size == 0u)
     35        return NULL;
     36 
     37    newData = (SECItem *)PORT_Alloc(sizeof(SECItem));
     38    if (newData == NULL)
     39        return NULL;
     40 
     41    newData->len = (data->len + (size - 1)) / size;
     42    newData->len *= size;
     43 
     44    newData->data = (unsigned char *)PORT_ZAlloc(newData->len);
     45    if (newData->data == NULL) {
     46        PORT_Free(newData);
     47        return NULL;
     48    }
     49    PORT_Memset(newData->data, newData->len - data->len, newData->len);
     50    PORT_Memcpy(newData->data, data->data, data->len);
     51    return newData;
     52 }
     53 
     54 SECStatus
     55 PK11_DestroyObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object)
     56 {
     57    CK_RV crv;
     58 
     59    PK11_EnterSlotMonitor(slot);
     60    crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session, object);
     61    PK11_ExitSlotMonitor(slot);
     62    if (crv != CKR_OK) {
     63        return SECFailure;
     64    }
     65    return SECSuccess;
     66 }
     67 
     68 SECStatus
     69 PK11_DestroyTokenObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object)
     70 {
     71    CK_RV crv;
     72    SECStatus rv = SECSuccess;
     73    CK_SESSION_HANDLE rwsession;
     74 
     75    rwsession = PK11_GetRWSession(slot);
     76    if (rwsession == CK_INVALID_HANDLE) {
     77        PORT_SetError(SEC_ERROR_BAD_DATA);
     78        return SECFailure;
     79    }
     80 
     81    crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession, object);
     82    if (crv != CKR_OK) {
     83        rv = SECFailure;
     84        PORT_SetError(PK11_MapError(crv));
     85    }
     86    PK11_RestoreROSession(slot, rwsession);
     87    return rv;
     88 }
     89 
     90 /*
     91 * Read in a single attribute into a SECItem. Allocate space for it with
     92 * PORT_Alloc unless an arena is supplied. In the latter case use the arena
     93 * to allocate the space.
     94 *
     95 * PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but
     96 * does not modify its 'type' field.
     97 */
     98 SECStatus
     99 PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
    100                   CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result)
    101 {
    102    CK_ATTRIBUTE attr = { 0, NULL, 0 };
    103    CK_RV crv;
    104 
    105    attr.type = type;
    106 
    107    PK11_EnterSlotMonitor(slot);
    108    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
    109    if (crv != CKR_OK) {
    110        PK11_ExitSlotMonitor(slot);
    111        PORT_SetError(PK11_MapError(crv));
    112        return SECFailure;
    113    }
    114    if (arena) {
    115        attr.pValue = PORT_ArenaAlloc(arena, attr.ulValueLen);
    116    } else {
    117        attr.pValue = PORT_Alloc(attr.ulValueLen);
    118    }
    119    if (attr.pValue == NULL) {
    120        PK11_ExitSlotMonitor(slot);
    121        return SECFailure;
    122    }
    123    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
    124    PK11_ExitSlotMonitor(slot);
    125    if (crv != CKR_OK) {
    126        PORT_SetError(PK11_MapError(crv));
    127        if (!arena)
    128            PORT_Free(attr.pValue);
    129        return SECFailure;
    130    }
    131 
    132    result->data = (unsigned char *)attr.pValue;
    133    result->len = attr.ulValueLen;
    134 
    135    return SECSuccess;
    136 }
    137 
    138 /*
    139 * Read in a single attribute into a Ulong.
    140 */
    141 CK_ULONG
    142 PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
    143                        CK_ATTRIBUTE_TYPE type)
    144 {
    145    CK_ATTRIBUTE attr;
    146    CK_ULONG value = CK_UNAVAILABLE_INFORMATION;
    147    CK_RV crv;
    148 
    149    PK11_SETATTRS(&attr, type, &value, sizeof(value));
    150 
    151    PK11_EnterSlotMonitor(slot);
    152    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
    153    PK11_ExitSlotMonitor(slot);
    154    if (crv != CKR_OK) {
    155        PORT_SetError(PK11_MapError(crv));
    156    }
    157    return value;
    158 }
    159 
    160 /*
    161 * check to see if a bool has been set.
    162 */
    163 CK_BBOOL
    164 pk11_HasAttributeSet_Lock(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
    165                          CK_ATTRIBUTE_TYPE type, PRBool haslock)
    166 {
    167    CK_BBOOL ckvalue = CK_FALSE;
    168    CK_ATTRIBUTE theTemplate;
    169    CK_RV crv;
    170 
    171    /* Prepare to retrieve the attribute. */
    172    PK11_SETATTRS(&theTemplate, type, &ckvalue, sizeof(CK_BBOOL));
    173 
    174    /* Retrieve attribute value. */
    175    if (!haslock)
    176        PK11_EnterSlotMonitor(slot);
    177    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id,
    178                                                 &theTemplate, 1);
    179    if (!haslock)
    180        PK11_ExitSlotMonitor(slot);
    181    if (crv != CKR_OK) {
    182        PORT_SetError(PK11_MapError(crv));
    183        return CK_FALSE;
    184    }
    185 
    186    return ckvalue;
    187 }
    188 
    189 CK_BBOOL
    190 PK11_HasAttributeSet(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
    191                     CK_ATTRIBUTE_TYPE type, PRBool haslock)
    192 {
    193    PR_ASSERT(haslock == PR_FALSE);
    194    return pk11_HasAttributeSet_Lock(slot, id, type, PR_FALSE);
    195 }
    196 
    197 /*
    198 * returns a full list of attributes. Allocate space for them. If an arena is
    199 * provided, allocate space out of the arena.
    200 */
    201 CK_RV
    202 PK11_GetAttributes(PLArenaPool *arena, PK11SlotInfo *slot,
    203                   CK_OBJECT_HANDLE obj, CK_ATTRIBUTE *attr, int count)
    204 {
    205    int i;
    206    /* make pedantic happy... note that it's only used arena != NULL */
    207    void *mark = NULL;
    208    CK_RV crv;
    209    if (slot->session == CK_INVALID_HANDLE)
    210        return CKR_SESSION_HANDLE_INVALID;
    211 
    212    /*
    213     * first get all the lengths of the parameters.
    214     */
    215    PK11_EnterSlotMonitor(slot);
    216    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count);
    217    if (crv != CKR_OK) {
    218        PK11_ExitSlotMonitor(slot);
    219        return crv;
    220    }
    221 
    222    if (arena) {
    223        mark = PORT_ArenaMark(arena);
    224        if (mark == NULL)
    225            return CKR_HOST_MEMORY;
    226    }
    227 
    228    /*
    229     * now allocate space to store the results.
    230     */
    231    for (i = 0; i < count; i++) {
    232        if (attr[i].ulValueLen == 0)
    233            continue;
    234        if (arena) {
    235            attr[i].pValue = PORT_ArenaAlloc(arena, attr[i].ulValueLen);
    236            if (attr[i].pValue == NULL) {
    237                /* arena failures, just release the mark */
    238                PORT_ArenaRelease(arena, mark);
    239                PK11_ExitSlotMonitor(slot);
    240                return CKR_HOST_MEMORY;
    241            }
    242        } else {
    243            attr[i].pValue = PORT_Alloc(attr[i].ulValueLen);
    244            if (attr[i].pValue == NULL) {
    245                /* Separate malloc failures, loop to release what we have
    246                 * so far */
    247                int j;
    248                for (j = 0; j < i; j++) {
    249                    PORT_Free(attr[j].pValue);
    250                    /* don't give the caller pointers to freed memory */
    251                    attr[j].pValue = NULL;
    252                }
    253                PK11_ExitSlotMonitor(slot);
    254                return CKR_HOST_MEMORY;
    255            }
    256        }
    257    }
    258 
    259    /*
    260     * finally get the results.
    261     */
    262    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count);
    263    PK11_ExitSlotMonitor(slot);
    264    if (crv != CKR_OK) {
    265        if (arena) {
    266            PORT_ArenaRelease(arena, mark);
    267        } else {
    268            for (i = 0; i < count; i++) {
    269                PORT_Free(attr[i].pValue);
    270                /* don't give the caller pointers to freed memory */
    271                attr[i].pValue = NULL;
    272            }
    273        }
    274    } else if (arena && mark) {
    275        PORT_ArenaUnmark(arena, mark);
    276    }
    277    return crv;
    278 }
    279 
    280 PRBool
    281 PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
    282 {
    283    return (PRBool)PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE);
    284 }
    285 
    286 char *
    287 PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
    288 {
    289    char *nickname = NULL;
    290    SECItem result;
    291    SECStatus rv;
    292 
    293    rv = PK11_ReadAttribute(slot, id, CKA_LABEL, NULL, &result);
    294    if (rv != SECSuccess) {
    295        return NULL;
    296    }
    297 
    298    nickname = PORT_ZAlloc(result.len + 1);
    299    if (nickname == NULL) {
    300        PORT_Free(result.data);
    301        return NULL;
    302    }
    303    PORT_Memcpy(nickname, result.data, result.len);
    304    PORT_Free(result.data);
    305    return nickname;
    306 }
    307 
    308 SECStatus
    309 PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
    310                       const char *nickname)
    311 {
    312    int len = PORT_Strlen(nickname);
    313    CK_ATTRIBUTE setTemplate;
    314    CK_RV crv;
    315    CK_SESSION_HANDLE rwsession;
    316 
    317    if (len < 0) {
    318        return SECFailure;
    319    }
    320 
    321    PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *)nickname, len);
    322    rwsession = PK11_GetRWSession(slot);
    323    if (rwsession == CK_INVALID_HANDLE) {
    324        PORT_SetError(SEC_ERROR_BAD_DATA);
    325        return SECFailure;
    326    }
    327    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
    328                                                 &setTemplate, 1);
    329    PK11_RestoreROSession(slot, rwsession);
    330    if (crv != CKR_OK) {
    331        PORT_SetError(PK11_MapError(crv));
    332        return SECFailure;
    333    }
    334    return SECSuccess;
    335 }
    336 
    337 /*
    338 * strip leading zero's from key material
    339 */
    340 void
    341 pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib)
    342 {
    343    char *ptr = (char *)attrib->pValue;
    344    unsigned long len = attrib->ulValueLen;
    345 
    346    while ((len > 1) && (*ptr == 0)) {
    347        len--;
    348        ptr++;
    349    }
    350    attrib->pValue = ptr;
    351    attrib->ulValueLen = len;
    352 }
    353 
    354 /*
    355 * get a new session on a slot. If we run out of session, use the slot's
    356 * 'exclusive' session. In this case owner becomes false.
    357 */
    358 CK_SESSION_HANDLE
    359 pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner)
    360 {
    361    CK_SESSION_HANDLE session;
    362    *owner = PR_TRUE;
    363    if (!slot->isThreadSafe)
    364        PK11_EnterSlotMonitor(slot);
    365    if (PK11_GETTAB(slot)->C_OpenSession(slot->slotID, CKF_SERIAL_SESSION,
    366                                         slot, pk11_notify, &session) != CKR_OK) {
    367        *owner = PR_FALSE;
    368        session = slot->session;
    369    }
    370    if (!slot->isThreadSafe)
    371        PK11_ExitSlotMonitor(slot);
    372 
    373    return session;
    374 }
    375 
    376 void
    377 pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE session, PRBool owner)
    378 {
    379    if (!owner)
    380        return;
    381    if (!slot->isThreadSafe)
    382        PK11_EnterSlotMonitor(slot);
    383    (void)PK11_GETTAB(slot)->C_CloseSession(session);
    384    if (!slot->isThreadSafe)
    385        PK11_ExitSlotMonitor(slot);
    386 }
    387 
    388 SECStatus
    389 PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
    390                     const CK_ATTRIBUTE *theTemplate, int count,
    391                     PRBool token, CK_OBJECT_HANDLE *objectID)
    392 {
    393    CK_SESSION_HANDLE rwsession;
    394    CK_RV crv;
    395    SECStatus rv = SECSuccess;
    396 
    397    rwsession = session;
    398    if (token) {
    399        rwsession = PK11_GetRWSession(slot);
    400    } else if (rwsession == CK_INVALID_HANDLE) {
    401        rwsession = slot->session;
    402        if (rwsession != CK_INVALID_HANDLE)
    403            PK11_EnterSlotMonitor(slot);
    404    }
    405    if (rwsession == CK_INVALID_HANDLE) {
    406        PORT_SetError(SEC_ERROR_BAD_DATA);
    407        return SECFailure;
    408    }
    409    crv = PK11_GETTAB(slot)->C_CreateObject(rwsession,
    410                                            /* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate,
    411                                            count, objectID);
    412    if (crv != CKR_OK) {
    413        PORT_SetError(PK11_MapError(crv));
    414        rv = SECFailure;
    415    }
    416    if (token) {
    417        PK11_RestoreROSession(slot, rwsession);
    418    } else if (session == CK_INVALID_HANDLE) {
    419        PK11_ExitSlotMonitor(slot);
    420    }
    421 
    422    return rv;
    423 }
    424 
    425 /* This function may add a maximum of 9 attributes. */
    426 unsigned int
    427 pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue)
    428 {
    429 
    430    const static CK_ATTRIBUTE_TYPE attrTypes[12] = {
    431        CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN,
    432        CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */,
    433        0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE
    434    };
    435 
    436    const CK_ATTRIBUTE_TYPE *pType = attrTypes;
    437    CK_ATTRIBUTE *attr = attrs;
    438    CK_FLAGS test = CKF_ENCRYPT;
    439 
    440    PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS));
    441    flags &= CKF_KEY_OPERATION_FLAGS;
    442 
    443    for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) {
    444        if (test & flags) {
    445            flags ^= test;
    446            PR_ASSERT(*pType);
    447            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
    448            ++attr;
    449        }
    450    }
    451    return (attr - attrs);
    452 }
    453 
    454 /*
    455 * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE
    456 * and PK11_ATTR_PUBLIC are set.
    457 */
    458 PRBool
    459 pk11_BadAttrFlags(PK11AttrFlags attrFlags)
    460 {
    461    PK11AttrFlags trueFlags = attrFlags & 0x55555555;
    462    PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555;
    463    return ((trueFlags & falseFlags) != 0);
    464 }
    465 
    466 /*
    467 * This function may add a maximum of 5 attributes.
    468 * The caller must make sure the attribute flags don't have conflicts.
    469 */
    470 unsigned int
    471 pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs,
    472                           CK_BBOOL *ckTrue, CK_BBOOL *ckFalse)
    473 {
    474    const static CK_ATTRIBUTE_TYPE attrTypes[5] = {
    475        CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE,
    476        CKA_EXTRACTABLE
    477    };
    478 
    479    const CK_ATTRIBUTE_TYPE *pType = attrTypes;
    480    CK_ATTRIBUTE *attr = attrs;
    481    PK11AttrFlags test = PK11_ATTR_TOKEN;
    482 
    483    PR_ASSERT(!pk11_BadAttrFlags(attrFlags));
    484 
    485    /* we test two related bitflags in each iteration */
    486    for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) {
    487        if (test & attrFlags) {
    488            attrFlags ^= test;
    489            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
    490            ++attr;
    491        } else if ((test << 1) & attrFlags) {
    492            attrFlags ^= (test << 1);
    493            PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse);
    494            ++attr;
    495        }
    496    }
    497    return (attr - attrs);
    498 }
    499 
    500 /*
    501 * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually
    502 * set up a signature to get the signaure length.
    503 */
    504 static int
    505 pk11_backupGetSignLength(SECKEYPrivateKey *key)
    506 {
    507    PK11SlotInfo *slot = key->pkcs11Slot;
    508    CK_MECHANISM mech = { 0, NULL, 0 };
    509    PRBool owner = PR_TRUE;
    510    CK_SESSION_HANDLE session;
    511    CK_ULONG len;
    512    CK_RV crv;
    513    unsigned char h_data[20] = { 0 };
    514    unsigned char buf[20]; /* obviously to small */
    515    CK_ULONG smallLen = sizeof(buf);
    516 
    517    mech.mechanism = PK11_MapSignKeyType(key->keyType);
    518 
    519    session = pk11_GetNewSession(slot, &owner);
    520    if (!owner || !(slot->isThreadSafe))
    521        PK11_EnterSlotMonitor(slot);
    522    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID);
    523    if (crv != CKR_OK) {
    524        if (!owner || !(slot->isThreadSafe))
    525            PK11_ExitSlotMonitor(slot);
    526        pk11_CloseSession(slot, session, owner);
    527        PORT_SetError(PK11_MapError(crv));
    528        return -1;
    529    }
    530    len = 0;
    531    crv = PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data),
    532                                    NULL, &len);
    533    /* now call C_Sign with too small a buffer to clear the session state */
    534    (void)PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data), buf, &smallLen);
    535 
    536    if (!owner || !(slot->isThreadSafe))
    537        PK11_ExitSlotMonitor(slot);
    538    pk11_CloseSession(slot, session, owner);
    539    if (crv != CKR_OK) {
    540        PORT_SetError(PK11_MapError(crv));
    541        return -1;
    542    }
    543    return len;
    544 }
    545 
    546 /*
    547 * get the length of a signature object based on the key
    548 */
    549 int
    550 PK11_SignatureLen(SECKEYPrivateKey *key)
    551 {
    552    int val;
    553    SECItem attributeItem = { siBuffer, NULL, 0 };
    554    SECStatus rv;
    555    int length;
    556    SECOidTag paramSet;
    557 
    558    switch (key->keyType) {
    559        case rsaKey:
    560        case rsaPssKey:
    561            val = PK11_GetPrivateModulusLen(key);
    562            if (val == -1) {
    563                return pk11_backupGetSignLength(key);
    564            }
    565            return (unsigned long)val;
    566 
    567        case fortezzaKey:
    568            return 40;
    569 
    570        case dsaKey:
    571            rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME,
    572                                    NULL, &attributeItem);
    573            if (rv == SECSuccess) {
    574                length = attributeItem.len;
    575                if ((length > 0) && attributeItem.data[0] == 0) {
    576                    length--;
    577                }
    578                PORT_Free(attributeItem.data);
    579                return length * 2;
    580            }
    581            return pk11_backupGetSignLength(key);
    582        case ecKey:
    583        case edKey:
    584            rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS,
    585                                    NULL, &attributeItem);
    586            if (rv == SECSuccess) {
    587                length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem);
    588                PORT_Free(attributeItem.data);
    589                if (length != 0) {
    590                    length = ((length + 7) / 8) * 2;
    591                    return length;
    592                }
    593            }
    594            return pk11_backupGetSignLength(key);
    595        case mldsaKey:
    596            paramSet = seckey_GetParameterSet(key);
    597            if (paramSet == SEC_OID_UNKNOWN) {
    598                break;
    599            }
    600 
    601            return SECKEY_MLDSAOidParamsToLen(paramSet, SECKEYSignatureType);
    602        default:
    603            break;
    604    }
    605    PORT_SetError(SEC_ERROR_INVALID_KEY);
    606    return 0;
    607 }
    608 
    609 /*
    610 * copy a key (or any other object) on a token
    611 */
    612 CK_OBJECT_HANDLE
    613 PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject)
    614 {
    615    CK_OBJECT_HANDLE destObject;
    616    CK_RV crv;
    617 
    618    PK11_EnterSlotMonitor(slot);
    619    crv = PK11_GETTAB(slot)->C_CopyObject(slot->session, srcObject, NULL, 0,
    620                                          &destObject);
    621    PK11_ExitSlotMonitor(slot);
    622    if (crv == CKR_OK)
    623        return destObject;
    624    PORT_SetError(PK11_MapError(crv));
    625    return CK_INVALID_HANDLE;
    626 }
    627 
    628 PRBool
    629 pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
    630                        CK_ATTRIBUTE_TYPE target)
    631 {
    632    for (; numAttrs > 0; ++attr, --numAttrs) {
    633        if (attr->type == target)
    634            return PR_TRUE;
    635    }
    636    return PR_FALSE;
    637 }
    638 
    639 /*
    640 * Recover the Signed data. We need this because our old verify can't
    641 * figure out which hash algorithm to use until we decryptted this.
    642 */
    643 SECStatus
    644 PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig,
    645                   SECItem *dsig, void *wincx)
    646 {
    647    PK11SlotInfo *slot = key->pkcs11Slot;
    648    CK_OBJECT_HANDLE id = key->pkcs11ID;
    649    CK_MECHANISM mech = { 0, NULL, 0 };
    650    PRBool owner = PR_TRUE;
    651    CK_SESSION_HANDLE session;
    652    CK_ULONG len;
    653    CK_RV crv;
    654 
    655    mech.mechanism = PK11_MapSignKeyType(key->keyType);
    656 
    657    if (slot == NULL) {
    658        slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
    659                                              CKF_VERIFY_RECOVER, 0, wincx);
    660        if (slot == NULL) {
    661            PORT_SetError(SEC_ERROR_NO_MODULE);
    662            return SECFailure;
    663        }
    664        id = PK11_ImportPublicKey(slot, key, PR_FALSE);
    665    } else {
    666        PK11_ReferenceSlot(slot);
    667    }
    668 
    669    if (id == CK_INVALID_HANDLE) {
    670        PK11_FreeSlot(slot);
    671        PORT_SetError(SEC_ERROR_BAD_KEY);
    672        return SECFailure;
    673    }
    674 
    675    session = pk11_GetNewSession(slot, &owner);
    676    if (!owner || !(slot->isThreadSafe))
    677        PK11_EnterSlotMonitor(slot);
    678    crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session, &mech, id);
    679    if (crv != CKR_OK) {
    680        if (!owner || !(slot->isThreadSafe))
    681            PK11_ExitSlotMonitor(slot);
    682        pk11_CloseSession(slot, session, owner);
    683        PORT_SetError(PK11_MapError(crv));
    684        PK11_FreeSlot(slot);
    685        return SECFailure;
    686    }
    687    len = dsig->len;
    688    crv = PK11_GETTAB(slot)->C_VerifyRecover(session, sig->data,
    689                                             sig->len, dsig->data, &len);
    690    if (!owner || !(slot->isThreadSafe))
    691        PK11_ExitSlotMonitor(slot);
    692    pk11_CloseSession(slot, session, owner);
    693    dsig->len = len;
    694    if (crv != CKR_OK) {
    695        PORT_SetError(PK11_MapError(crv));
    696        PK11_FreeSlot(slot);
    697        return SECFailure;
    698    }
    699    PK11_FreeSlot(slot);
    700    return SECSuccess;
    701 }
    702 
    703 /*
    704 * verify a signature from its hash.
    705 */
    706 SECStatus
    707 PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash,
    708            void *wincx)
    709 {
    710    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
    711    return PK11_VerifyWithMechanism(key, mech, NULL, sig, hash, wincx);
    712 }
    713 
    714 /*
    715 * Verify a signature from its hash using the given algorithm.
    716 */
    717 SECStatus
    718 PK11_VerifyWithMechanism(SECKEYPublicKey *key, CK_MECHANISM_TYPE mechanism,
    719                         const SECItem *param, const SECItem *sig,
    720                         const SECItem *hash, void *wincx)
    721 {
    722    PK11SlotInfo *slot = key->pkcs11Slot;
    723    CK_OBJECT_HANDLE id = key->pkcs11ID;
    724    CK_MECHANISM mech = { 0, NULL, 0 };
    725    PRBool owner = PR_TRUE;
    726    CK_SESSION_HANDLE session;
    727    CK_RV crv;
    728 
    729    mech.mechanism = mechanism;
    730    if (param) {
    731        mech.pParameter = param->data;
    732        mech.ulParameterLen = param->len;
    733    }
    734 
    735    if (slot == NULL) {
    736        unsigned int length = 0;
    737        if ((mech.mechanism == CKM_DSA) &&
    738            /* 129 is 1024 bits translated to bytes and
    739             * padded with an optional '0' to maintain a
    740             * positive sign */
    741            (key->u.dsa.params.prime.len > 129)) {
    742            /* we need to get a slot that not only can do DSA, but can do DSA2
    743             * key lengths */
    744            length = key->u.dsa.params.prime.len;
    745            if (key->u.dsa.params.prime.data[0] == 0) {
    746                length--;
    747            }
    748            /* convert keysize to bits for slot lookup */
    749            length *= 8;
    750        }
    751        slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
    752                                              CKF_VERIFY, length, wincx);
    753        if (slot == NULL) {
    754            PORT_SetError(SEC_ERROR_NO_MODULE);
    755            return SECFailure;
    756        }
    757        id = PK11_ImportPublicKey(slot, key, PR_FALSE);
    758 
    759    } else {
    760        PK11_ReferenceSlot(slot);
    761    }
    762 
    763    if (id == CK_INVALID_HANDLE) {
    764        PK11_FreeSlot(slot);
    765        PORT_SetError(SEC_ERROR_BAD_KEY);
    766        return SECFailure;
    767    }
    768 
    769    session = pk11_GetNewSession(slot, &owner);
    770    if (!owner || !(slot->isThreadSafe))
    771        PK11_EnterSlotMonitor(slot);
    772    if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) {
    773        crv = PK11_GETTAB(slot)->C_VerifySignatureInit(session, &mech, id,
    774                                                       sig->data, sig->len);
    775        if (crv != CKR_OK) {
    776            if (!owner || !(slot->isThreadSafe))
    777                PK11_ExitSlotMonitor(slot);
    778            pk11_CloseSession(slot, session, owner);
    779            PK11_FreeSlot(slot);
    780            PORT_SetError(PK11_MapError(crv));
    781            return SECFailure;
    782        }
    783        crv = PK11_GETTAB(slot)->C_VerifySignature(session, hash->data,
    784                                                   hash->len);
    785    } else {
    786        crv = PK11_GETTAB(slot)->C_VerifyInit(session, &mech, id);
    787        if (crv != CKR_OK) {
    788            if (!owner || !(slot->isThreadSafe))
    789                PK11_ExitSlotMonitor(slot);
    790            pk11_CloseSession(slot, session, owner);
    791            PK11_FreeSlot(slot);
    792            PORT_SetError(PK11_MapError(crv));
    793            return SECFailure;
    794        }
    795        crv = PK11_GETTAB(slot)->C_Verify(session, hash->data,
    796                                          hash->len, sig->data, sig->len);
    797    }
    798    if (!owner || !(slot->isThreadSafe))
    799        PK11_ExitSlotMonitor(slot);
    800 
    801    pk11_CloseSession(slot, session, owner);
    802    PK11_FreeSlot(slot);
    803    if (crv != CKR_OK) {
    804        PORT_SetError(PK11_MapError(crv));
    805        return SECFailure;
    806    }
    807    return SECSuccess;
    808 }
    809 
    810 /*
    811 * sign a hash. The algorithm is determined by the key.
    812 */
    813 SECStatus
    814 PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash)
    815 {
    816    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
    817    return PK11_SignWithMechanism(key, mech, NULL, sig, hash);
    818 }
    819 
    820 /*
    821 * Sign a hash using the given algorithm.
    822 */
    823 SECStatus
    824 PK11_SignWithMechanism(SECKEYPrivateKey *key, CK_MECHANISM_TYPE mechanism,
    825                       const SECItem *param, SECItem *sig, const SECItem *hash)
    826 {
    827    PK11SlotInfo *slot = key->pkcs11Slot;
    828    CK_MECHANISM mech = { 0, NULL, 0 };
    829    PRBool owner = PR_TRUE;
    830    CK_SESSION_HANDLE session;
    831    PRBool haslock = PR_FALSE;
    832    CK_ULONG len;
    833    CK_RV crv;
    834 
    835    mech.mechanism = mechanism;
    836    if (param) {
    837        mech.pParameter = param->data;
    838        mech.ulParameterLen = param->len;
    839    }
    840 
    841    if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) {
    842        PK11_HandlePasswordCheck(slot, key->wincx);
    843    }
    844 
    845    session = pk11_GetNewSession(slot, &owner);
    846    haslock = (!owner || !(slot->isThreadSafe));
    847    if (haslock)
    848        PK11_EnterSlotMonitor(slot);
    849    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID);
    850    if (crv != CKR_OK) {
    851        if (haslock)
    852            PK11_ExitSlotMonitor(slot);
    853        pk11_CloseSession(slot, session, owner);
    854        PORT_SetError(PK11_MapError(crv));
    855        return SECFailure;
    856    }
    857 
    858    /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
    859     * do C_Login with CKU_CONTEXT_SPECIFIC
    860     * between C_SignInit and C_Sign */
    861    if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
    862        PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
    863    }
    864 
    865    len = sig->len;
    866    crv = PK11_GETTAB(slot)->C_Sign(session, hash->data,
    867                                    hash->len, sig->data, &len);
    868    if (haslock)
    869        PK11_ExitSlotMonitor(slot);
    870    pk11_CloseSession(slot, session, owner);
    871    sig->len = len;
    872    if (crv != CKR_OK) {
    873        PORT_SetError(PK11_MapError(crv));
    874        return SECFailure;
    875    }
    876    return SECSuccess;
    877 }
    878 
    879 /*
    880 * sign data with a MAC key.
    881 */
    882 SECStatus
    883 PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism,
    884                    SECItem *param, SECItem *sig, const SECItem *data)
    885 {
    886    PK11SlotInfo *slot = symKey->slot;
    887    CK_MECHANISM mech = { 0, NULL, 0 };
    888    PRBool owner = PR_TRUE;
    889    CK_SESSION_HANDLE session;
    890    PRBool haslock = PR_FALSE;
    891    CK_ULONG len;
    892    CK_RV crv;
    893 
    894    mech.mechanism = mechanism;
    895    if (param) {
    896        mech.pParameter = param->data;
    897        mech.ulParameterLen = param->len;
    898    }
    899 
    900    session = pk11_GetNewSession(slot, &owner);
    901    haslock = (!owner || !(slot->isThreadSafe));
    902    if (haslock)
    903        PK11_EnterSlotMonitor(slot);
    904    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, symKey->objectID);
    905    if (crv != CKR_OK) {
    906        if (haslock)
    907            PK11_ExitSlotMonitor(slot);
    908        pk11_CloseSession(slot, session, owner);
    909        PORT_SetError(PK11_MapError(crv));
    910        return SECFailure;
    911    }
    912 
    913    len = sig->len;
    914    crv = PK11_GETTAB(slot)->C_Sign(session, data->data,
    915                                    data->len, sig->data, &len);
    916    if (haslock)
    917        PK11_ExitSlotMonitor(slot);
    918    pk11_CloseSession(slot, session, owner);
    919    sig->len = len;
    920    if (crv != CKR_OK) {
    921        PORT_SetError(PK11_MapError(crv));
    922        return SECFailure;
    923    }
    924    return SECSuccess;
    925 }
    926 
    927 SECStatus
    928 PK11_Decrypt(PK11SymKey *symKey,
    929             CK_MECHANISM_TYPE mechanism, SECItem *param,
    930             unsigned char *out, unsigned int *outLen,
    931             unsigned int maxLen,
    932             const unsigned char *enc, unsigned encLen)
    933 {
    934    PK11SlotInfo *slot = symKey->slot;
    935    CK_MECHANISM mech = { 0, NULL, 0 };
    936    CK_ULONG len = maxLen;
    937    PRBool owner = PR_TRUE;
    938    CK_SESSION_HANDLE session;
    939    PRBool haslock = PR_FALSE;
    940    CK_RV crv;
    941 
    942    mech.mechanism = mechanism;
    943    if (param) {
    944        mech.pParameter = param->data;
    945        mech.ulParameterLen = param->len;
    946    }
    947 
    948    session = pk11_GetNewSession(slot, &owner);
    949    haslock = (!owner || !slot->isThreadSafe);
    950    if (haslock)
    951        PK11_EnterSlotMonitor(slot);
    952    crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID);
    953    if (crv != CKR_OK) {
    954        if (haslock)
    955            PK11_ExitSlotMonitor(slot);
    956        pk11_CloseSession(slot, session, owner);
    957        PORT_SetError(PK11_MapError(crv));
    958        return SECFailure;
    959    }
    960 
    961    crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
    962                                       out, &len);
    963    if (haslock)
    964        PK11_ExitSlotMonitor(slot);
    965    pk11_CloseSession(slot, session, owner);
    966    if (crv != CKR_OK) {
    967        PORT_SetError(PK11_MapError(crv));
    968        return SECFailure;
    969    }
    970    *outLen = len;
    971    return SECSuccess;
    972 }
    973 
    974 SECStatus
    975 PK11_Encrypt(PK11SymKey *symKey,
    976             CK_MECHANISM_TYPE mechanism, SECItem *param,
    977             unsigned char *out, unsigned int *outLen,
    978             unsigned int maxLen,
    979             const unsigned char *data, unsigned int dataLen)
    980 {
    981    PK11SlotInfo *slot = symKey->slot;
    982    CK_MECHANISM mech = { 0, NULL, 0 };
    983    CK_ULONG len = maxLen;
    984    PRBool owner = PR_TRUE;
    985    CK_SESSION_HANDLE session;
    986    PRBool haslock = PR_FALSE;
    987    CK_RV crv;
    988 
    989    mech.mechanism = mechanism;
    990    if (param) {
    991        mech.pParameter = param->data;
    992        mech.ulParameterLen = param->len;
    993    }
    994 
    995    session = pk11_GetNewSession(slot, &owner);
    996    haslock = (!owner || !slot->isThreadSafe);
    997    if (haslock)
    998        PK11_EnterSlotMonitor(slot);
    999    crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID);
   1000    if (crv != CKR_OK) {
   1001        if (haslock)
   1002            PK11_ExitSlotMonitor(slot);
   1003        pk11_CloseSession(slot, session, owner);
   1004        PORT_SetError(PK11_MapError(crv));
   1005        return SECFailure;
   1006    }
   1007    crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data,
   1008                                       dataLen, out, &len);
   1009    if (haslock)
   1010        PK11_ExitSlotMonitor(slot);
   1011    pk11_CloseSession(slot, session, owner);
   1012    if (crv != CKR_OK) {
   1013        PORT_SetError(PK11_MapError(crv));
   1014        return SECFailure;
   1015    }
   1016    *outLen = len;
   1017    return SECSuccess;
   1018 }
   1019 
   1020 static SECStatus
   1021 pk11_PrivDecryptRaw(SECKEYPrivateKey *key,
   1022                    unsigned char *data, unsigned *outLen, unsigned int maxLen,
   1023                    const unsigned char *enc, unsigned encLen,
   1024                    CK_MECHANISM_PTR mech)
   1025 {
   1026    PK11SlotInfo *slot = key->pkcs11Slot;
   1027    CK_ULONG out = maxLen;
   1028    PRBool owner = PR_TRUE;
   1029    CK_SESSION_HANDLE session;
   1030    PRBool haslock = PR_FALSE;
   1031    CK_RV crv;
   1032 
   1033    if (key->keyType != rsaKey) {
   1034        PORT_SetError(SEC_ERROR_INVALID_KEY);
   1035        return SECFailure;
   1036    }
   1037 
   1038    /* Why do we do a PK11_handle check here? for simple
   1039     * decryption? .. because the user may have asked for 'ask always'
   1040     * and this is a private key operation. In practice, thought, it's mute
   1041     * since only servers wind up using this function */
   1042    if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) {
   1043        PK11_HandlePasswordCheck(slot, key->wincx);
   1044    }
   1045    session = pk11_GetNewSession(slot, &owner);
   1046    haslock = (!owner || !(slot->isThreadSafe));
   1047    if (haslock)
   1048        PK11_EnterSlotMonitor(slot);
   1049    crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID);
   1050    if (crv != CKR_OK) {
   1051        if (haslock)
   1052            PK11_ExitSlotMonitor(slot);
   1053        pk11_CloseSession(slot, session, owner);
   1054        PORT_SetError(PK11_MapError(crv));
   1055        return SECFailure;
   1056    }
   1057 
   1058    /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
   1059     * do C_Login with CKU_CONTEXT_SPECIFIC
   1060     * between C_DecryptInit and C_Decrypt
   1061     * ... But see note above about servers */
   1062    if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
   1063        PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
   1064    }
   1065 
   1066    crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
   1067                                       data, &out);
   1068    if (haslock)
   1069        PK11_ExitSlotMonitor(slot);
   1070    pk11_CloseSession(slot, session, owner);
   1071    *outLen = out;
   1072    if (crv != CKR_OK) {
   1073        PORT_SetError(PK11_MapError(crv));
   1074        return SECFailure;
   1075    }
   1076    return SECSuccess;
   1077 }
   1078 
   1079 SECStatus
   1080 PK11_PubDecryptRaw(SECKEYPrivateKey *key,
   1081                   unsigned char *data, unsigned *outLen, unsigned int maxLen,
   1082                   const unsigned char *enc, unsigned encLen)
   1083 {
   1084    CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 };
   1085    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
   1086 }
   1087 
   1088 SECStatus
   1089 PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key,
   1090                      unsigned char *data, unsigned *outLen, unsigned int maxLen,
   1091                      const unsigned char *enc, unsigned encLen)
   1092 {
   1093    CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 };
   1094    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
   1095 }
   1096 
   1097 static SECStatus
   1098 pk11_PubEncryptRaw(SECKEYPublicKey *key,
   1099                   unsigned char *out, unsigned int *outLen,
   1100                   unsigned int maxLen,
   1101                   const unsigned char *data, unsigned dataLen,
   1102                   CK_MECHANISM_PTR mech, void *wincx)
   1103 {
   1104    PK11SlotInfo *slot;
   1105    CK_OBJECT_HANDLE id;
   1106    CK_ULONG len = maxLen;
   1107    PRBool owner = PR_TRUE;
   1108    CK_SESSION_HANDLE session;
   1109    CK_RV crv;
   1110 
   1111    slot = PK11_GetBestSlotWithAttributes(mech->mechanism, CKF_ENCRYPT, 0, wincx);
   1112    if (slot == NULL) {
   1113        PORT_SetError(SEC_ERROR_NO_MODULE);
   1114        return SECFailure;
   1115    }
   1116 
   1117    id = PK11_ImportPublicKey(slot, key, PR_FALSE);
   1118 
   1119    if (id == CK_INVALID_HANDLE) {
   1120        PK11_FreeSlot(slot);
   1121        PORT_SetError(SEC_ERROR_BAD_KEY);
   1122        return SECFailure;
   1123    }
   1124 
   1125    session = pk11_GetNewSession(slot, &owner);
   1126    if (!owner || !(slot->isThreadSafe))
   1127        PK11_EnterSlotMonitor(slot);
   1128    crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id);
   1129    if (crv != CKR_OK) {
   1130        if (!owner || !(slot->isThreadSafe))
   1131            PK11_ExitSlotMonitor(slot);
   1132        pk11_CloseSession(slot, session, owner);
   1133        PK11_FreeSlot(slot);
   1134        PORT_SetError(PK11_MapError(crv));
   1135        return SECFailure;
   1136    }
   1137    crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, dataLen,
   1138                                       out, &len);
   1139    if (!owner || !(slot->isThreadSafe))
   1140        PK11_ExitSlotMonitor(slot);
   1141    pk11_CloseSession(slot, session, owner);
   1142    PK11_FreeSlot(slot);
   1143    *outLen = len;
   1144    if (crv != CKR_OK) {
   1145        PORT_SetError(PK11_MapError(crv));
   1146        return SECFailure;
   1147    }
   1148    return SECSuccess;
   1149 }
   1150 
   1151 SECStatus
   1152 PK11_PubEncryptRaw(SECKEYPublicKey *key,
   1153                   unsigned char *enc,
   1154                   const unsigned char *data, unsigned dataLen,
   1155                   void *wincx)
   1156 {
   1157    CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 };
   1158    unsigned int outLen;
   1159    if (!key || key->keyType != rsaKey) {
   1160        PORT_SetError(SEC_ERROR_BAD_KEY);
   1161        return SECFailure;
   1162    }
   1163    outLen = SECKEY_PublicKeyStrength(key);
   1164    return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
   1165                              wincx);
   1166 }
   1167 
   1168 SECStatus
   1169 PK11_PubEncryptPKCS1(SECKEYPublicKey *key,
   1170                     unsigned char *enc,
   1171                     const unsigned char *data, unsigned dataLen,
   1172                     void *wincx)
   1173 {
   1174    CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 };
   1175    unsigned int outLen;
   1176    if (!key || key->keyType != rsaKey) {
   1177        PORT_SetError(SEC_ERROR_BAD_KEY);
   1178        return SECFailure;
   1179    }
   1180    outLen = SECKEY_PublicKeyStrength(key);
   1181    return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
   1182                              wincx);
   1183 }
   1184 
   1185 SECStatus
   1186 PK11_PrivDecrypt(SECKEYPrivateKey *key,
   1187                 CK_MECHANISM_TYPE mechanism, SECItem *param,
   1188                 unsigned char *out, unsigned int *outLen,
   1189                 unsigned int maxLen,
   1190                 const unsigned char *enc, unsigned encLen)
   1191 {
   1192    CK_MECHANISM mech = { mechanism, NULL, 0 };
   1193    if (param) {
   1194        mech.pParameter = param->data;
   1195        mech.ulParameterLen = param->len;
   1196    }
   1197    return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech);
   1198 }
   1199 
   1200 SECStatus
   1201 PK11_PubEncrypt(SECKEYPublicKey *key,
   1202                CK_MECHANISM_TYPE mechanism, SECItem *param,
   1203                unsigned char *out, unsigned int *outLen,
   1204                unsigned int maxLen,
   1205                const unsigned char *data, unsigned dataLen,
   1206                void *wincx)
   1207 {
   1208    CK_MECHANISM mech = { mechanism, NULL, 0 };
   1209    if (param) {
   1210        mech.pParameter = param->data;
   1211        mech.ulParameterLen = param->len;
   1212    }
   1213    return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech,
   1214                              wincx);
   1215 }
   1216 
   1217 SECKEYPrivateKey *
   1218 PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
   1219                   CK_MECHANISM_TYPE wrapType, SECItem *param,
   1220                   SECItem *wrappedKey, SECItem *label,
   1221                   const SECItem *idValue, PRBool perm, PRBool sensitive,
   1222                   CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage,
   1223                   int usageCount, void *wincx)
   1224 {
   1225    CK_BBOOL cktrue = CK_TRUE;
   1226    CK_BBOOL ckfalse = CK_FALSE;
   1227    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
   1228    CK_ATTRIBUTE keyTemplate[15];
   1229    int templateCount = 0;
   1230    CK_OBJECT_HANDLE privKeyID;
   1231    CK_MECHANISM mechanism;
   1232    CK_ATTRIBUTE *attrs = keyTemplate;
   1233    SECItem *param_free = NULL, *ck_id = NULL;
   1234    CK_RV crv;
   1235    CK_SESSION_HANDLE rwsession;
   1236    PK11SymKey *newKey = NULL;
   1237    int i;
   1238 
   1239    if (!slot || !wrappedKey || !idValue) {
   1240        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1241        return NULL;
   1242    }
   1243 
   1244    ck_id = PK11_MakeIDFromPubKey(idValue);
   1245    if (!ck_id) {
   1246        return NULL;
   1247    }
   1248 
   1249    PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse,
   1250                  sizeof(cktrue));
   1251    attrs++;
   1252    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
   1253    attrs++;
   1254    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
   1255    attrs++;
   1256    PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse,
   1257                  sizeof(cktrue));
   1258    attrs++;
   1259    PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse,
   1260                  sizeof(cktrue));
   1261    attrs++;
   1262    if (label && label->data) {
   1263        PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len);
   1264        attrs++;
   1265    }
   1266    PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
   1267    attrs++;
   1268    for (i = 0; i < usageCount; i++) {
   1269        PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue));
   1270        attrs++;
   1271    }
   1272 
   1273    if (PK11_IsInternal(slot)) {
   1274        PK11_SETATTRS(attrs, CKA_NSS_DB, idValue->data,
   1275                      idValue->len);
   1276        attrs++;
   1277    }
   1278 
   1279    templateCount = attrs - keyTemplate;
   1280    PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)));
   1281 
   1282    mechanism.mechanism = wrapType;
   1283    if (!param)
   1284        param = param_free = PK11_ParamFromIV(wrapType, NULL);
   1285    if (param) {
   1286        mechanism.pParameter = param->data;
   1287        mechanism.ulParameterLen = param->len;
   1288    } else {
   1289        mechanism.pParameter = NULL;
   1290        mechanism.ulParameterLen = 0;
   1291    }
   1292 
   1293    if (wrappingKey->slot != slot) {
   1294        newKey = pk11_CopyToSlot(slot, wrapType, CKA_UNWRAP, wrappingKey);
   1295    } else {
   1296        newKey = PK11_ReferenceSymKey(wrappingKey);
   1297    }
   1298 
   1299    if (newKey) {
   1300        if (perm) {
   1301            /* Get RW Session will either lock the monitor if necessary,
   1302             *  or return a thread safe session handle, or fail. */
   1303            rwsession = PK11_GetRWSession(slot);
   1304        } else {
   1305            rwsession = slot->session;
   1306            if (rwsession != CK_INVALID_HANDLE)
   1307                PK11_EnterSlotMonitor(slot);
   1308        }
   1309        /* This is a lot a work to deal with fussy PKCS #11 modules
   1310         * that can't bother to return BAD_DATA when presented with an
   1311         * invalid session! */
   1312        if (rwsession == CK_INVALID_HANDLE) {
   1313            PORT_SetError(SEC_ERROR_BAD_DATA);
   1314            goto loser;
   1315        }
   1316        crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism,
   1317                                             newKey->objectID,
   1318                                             wrappedKey->data,
   1319                                             wrappedKey->len, keyTemplate,
   1320                                             templateCount, &privKeyID);
   1321 
   1322        if (perm) {
   1323            PK11_RestoreROSession(slot, rwsession);
   1324        } else {
   1325            PK11_ExitSlotMonitor(slot);
   1326        }
   1327        PK11_FreeSymKey(newKey);
   1328        newKey = NULL;
   1329    } else {
   1330        crv = CKR_FUNCTION_NOT_SUPPORTED;
   1331    }
   1332 
   1333    SECITEM_FreeItem(ck_id, PR_TRUE);
   1334    ck_id = NULL;
   1335 
   1336    if (crv != CKR_OK) {
   1337        /* we couldn't unwrap the key, use the internal module to do the
   1338         * unwrap, then load the new key into the token */
   1339        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
   1340 
   1341        if (int_slot && (slot != int_slot)) {
   1342            SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
   1343                                                           wrappingKey, wrapType, param, wrappedKey, label,
   1344                                                           idValue, PR_FALSE, PR_FALSE,
   1345                                                           keyType, usage, usageCount, wincx);
   1346            if (privKey) {
   1347                SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot, privKey,
   1348                                                                NULL, perm, sensitive);
   1349                SECKEY_DestroyPrivateKey(privKey);
   1350                PK11_FreeSlot(int_slot);
   1351                SECITEM_FreeItem(param_free, PR_TRUE);
   1352                return newPrivKey;
   1353            }
   1354        }
   1355        if (int_slot)
   1356            PK11_FreeSlot(int_slot);
   1357        PORT_SetError(PK11_MapError(crv));
   1358        SECITEM_FreeItem(param_free, PR_TRUE);
   1359        return NULL;
   1360    }
   1361    SECITEM_FreeItem(param_free, PR_TRUE);
   1362    return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx);
   1363 
   1364 loser:
   1365    PK11_FreeSymKey(newKey);
   1366    SECITEM_FreeItem(ck_id, PR_TRUE);
   1367    SECITEM_FreeItem(param_free, PR_TRUE);
   1368    return NULL;
   1369 }
   1370 
   1371 /*
   1372 * PK11_UnwrapPrivKeyByKeyType is like PK11_UnwrapPrivKey but uses the
   1373 * keyType and the keyUsage to determine what usage attributes to set.
   1374 */
   1375 #define _MAX_USAGE 6
   1376 SECKEYPrivateKey *
   1377 PK11_UnwrapPrivKeyByKeyType(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
   1378                            CK_MECHANISM_TYPE wrapType, SECItem *param,
   1379                            SECItem *wrappedKey, SECItem *label,
   1380                            const SECItem *idValue, PRBool perm, PRBool sensitive,
   1381                            KeyType keyType, unsigned int keyUsage, void *wincx)
   1382 {
   1383    CK_KEY_TYPE pk11KeyType = pk11_getPKCS11KeyTypeFromKeyType(keyType);
   1384    CK_ATTRIBUTE_TYPE usage[_MAX_USAGE];
   1385    int usageCount = 0;
   1386    PRBool needKeyUsage = PR_FALSE;
   1387 
   1388    /* RSA and ecKeys can be used in more than one usage, use the
   1389     * key usage to determine which usage to actual set */
   1390    if ((keyType == rsaKey) || (keyType == ecKey)) {
   1391        needKeyUsage = PR_TRUE;
   1392    }
   1393 
   1394    /* use the pk11_mapXXXXKeyType functions to determine what kind
   1395     * of attributes to set on the key. Using these functions reduces
   1396     * the number of places we need to update to add new key types */
   1397    if ((pk11_mapWrapKeyType(keyType) != CKM_INVALID_MECHANISM) &&
   1398        (!needKeyUsage || keyUsage & KU_KEY_ENCIPHERMENT)) {
   1399        usage[usageCount++] = CKA_UNWRAP;
   1400        usage[usageCount++] = CKA_DECRYPT;
   1401    }
   1402    if ((pk11_mapKemKeyType(keyType) != CKM_INVALID_MECHANISM) &&
   1403        (!needKeyUsage || keyUsage & KU_KEY_AGREEMENT)) {
   1404        usage[usageCount++] = CKA_DECAPSULATE;
   1405    }
   1406    if ((PK11_MapSignKeyType(keyType) != CKM_INVALID_MECHANISM) &&
   1407        (!needKeyUsage || keyUsage & KU_DIGITAL_SIGNATURE)) {
   1408        usage[usageCount++] = CKA_SIGN;
   1409        if (keyType == rsaKey) {
   1410            usage[usageCount++] = CKA_SIGN_RECOVER;
   1411        }
   1412    }
   1413    if ((pk11_mapDeriveKeyType(keyType) != CKM_INVALID_MECHANISM) &&
   1414        (!needKeyUsage || keyUsage & KU_KEY_AGREEMENT)) {
   1415        usage[usageCount++] = CKA_DERIVE;
   1416    }
   1417 
   1418    PORT_Assert(usageCount <= _MAX_USAGE);
   1419 
   1420    if (usageCount == 0) {
   1421        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1422    }
   1423    return PK11_UnwrapPrivKey(slot, wrappingKey, wrapType, param, wrappedKey,
   1424                              label, idValue, perm, sensitive, pk11KeyType,
   1425                              usage, usageCount, wincx);
   1426 }
   1427 
   1428 /*
   1429 * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey
   1430 * The strategy is to get both keys to reside in the same slot,
   1431 * one that can perform the desired crypto mechanism and then
   1432 * call C_WrapKey after all the setup has taken place.
   1433 */
   1434 SECStatus
   1435 PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
   1436                 SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType,
   1437                 SECItem *param, SECItem *wrappedKey, void *wincx)
   1438 {
   1439    PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where
   1440                                                   * the private key
   1441                                                   * we are going to
   1442                                                   * wrap lives.
   1443                                                   */
   1444    PK11SymKey *newSymKey = NULL;
   1445    SECKEYPrivateKey *newPrivKey = NULL;
   1446    SECItem *param_free = NULL;
   1447    CK_ULONG len = wrappedKey->len;
   1448    CK_MECHANISM mech;
   1449    CK_RV crv;
   1450 
   1451    if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) {
   1452        /* Figure out a slot that does the mechanism and try to import
   1453         * the private key onto that slot.
   1454         */
   1455        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
   1456 
   1457        privSlot = int_slot; /* The private key has a new home */
   1458        newPrivKey = PK11_LoadPrivKey(privSlot, privKey, NULL, PR_FALSE, PR_FALSE);
   1459        /* newPrivKey has allocated its own reference to the slot, so it's
   1460         * safe until we destroy newPrivkey.
   1461         */
   1462        PK11_FreeSlot(int_slot);
   1463        if (newPrivKey == NULL) {
   1464            return SECFailure;
   1465        }
   1466        privKey = newPrivKey;
   1467    }
   1468 
   1469    if (privSlot != wrappingKey->slot) {
   1470        newSymKey = pk11_CopyToSlot(privSlot, wrapType, CKA_WRAP,
   1471                                    wrappingKey);
   1472        wrappingKey = newSymKey;
   1473    }
   1474 
   1475    if (wrappingKey == NULL) {
   1476        if (newPrivKey) {
   1477            SECKEY_DestroyPrivateKey(newPrivKey);
   1478        }
   1479        return SECFailure;
   1480    }
   1481    mech.mechanism = wrapType;
   1482    if (!param) {
   1483        param = param_free = PK11_ParamFromIV(wrapType, NULL);
   1484    }
   1485    if (param) {
   1486        mech.pParameter = param->data;
   1487        mech.ulParameterLen = param->len;
   1488    } else {
   1489        mech.pParameter = NULL;
   1490        mech.ulParameterLen = 0;
   1491    }
   1492 
   1493    PK11_EnterSlotMonitor(privSlot);
   1494    crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech,
   1495                                           wrappingKey->objectID,
   1496                                           privKey->pkcs11ID,
   1497                                           wrappedKey->data, &len);
   1498    PK11_ExitSlotMonitor(privSlot);
   1499 
   1500    if (newSymKey) {
   1501        PK11_FreeSymKey(newSymKey);
   1502    }
   1503    if (newPrivKey) {
   1504        SECKEY_DestroyPrivateKey(newPrivKey);
   1505    }
   1506    if (param_free) {
   1507        SECITEM_FreeItem(param_free, PR_TRUE);
   1508    }
   1509 
   1510    if (crv != CKR_OK) {
   1511        PORT_SetError(PK11_MapError(crv));
   1512        return SECFailure;
   1513    }
   1514 
   1515    wrappedKey->len = len;
   1516    return SECSuccess;
   1517 }
   1518 
   1519 #if 0
   1520 /*
   1521 * Sample code relating to linked list returned by PK11_FindGenericObjects
   1522 */
   1523 
   1524 /*
   1525 * You can walk the list with the following code:
   1526 */
   1527    firstObj = PK11_FindGenericObjects(slot, objClass);
   1528    for (thisObj=firstObj;
   1529         thisObj;
   1530         thisObj=PK11_GetNextGenericObject(thisObj)) {
   1531        /* operate on thisObj */
   1532    }
   1533 /*
   1534 * If you want a particular object from the list...
   1535 */
   1536    firstObj = PK11_FindGenericObjects(slot, objClass);
   1537    for (thisObj=firstObj;
   1538         thisObj;
   1539         thisObj=PK11_GetNextGenericObject(thisObj)) {
   1540      if (isMyObj(thisObj)) {
   1541       if ( thisObj == firstObj) {
   1542                /* NOTE: firstObj could be NULL at this point */
   1543      firstObj = PK11_GetNextGenericObject(thsObj);
   1544       }
   1545       PK11_UnlinkGenericObject(thisObj);
   1546            myObj = thisObj;
   1547            break;
   1548        }
   1549    }
   1550 
   1551    PK11_DestroyGenericObjects(firstObj);
   1552 
   1553      /* use myObj */
   1554 
   1555    PK11_DestroyGenericObject(myObj);
   1556 #endif /* sample code */
   1557 
   1558 /*
   1559 * return a linked, non-circular list of generic objects.
   1560 * If you are only interested
   1561 * in one object, just use the first object in the list. To find the
   1562 * rest of the list use PK11_GetNextGenericObject() to return the next object.
   1563 */
   1564 PK11GenericObject *
   1565 PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass)
   1566 {
   1567    CK_ATTRIBUTE template[1];
   1568    CK_ATTRIBUTE *attrs = template;
   1569    CK_OBJECT_HANDLE *objectIDs = NULL;
   1570    PK11GenericObject *lastObj = NULL, *obj;
   1571    PK11GenericObject *firstObj = NULL;
   1572    int i, count = 0;
   1573 
   1574    PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass));
   1575    attrs++;
   1576 
   1577    objectIDs = pk11_FindObjectsByTemplate(slot, template, 1, &count);
   1578    if (objectIDs == NULL) {
   1579        return NULL;
   1580    }
   1581 
   1582    /* where we connect our object once we've created it.. */
   1583    for (i = 0; i < count; i++) {
   1584        obj = PORT_New(PK11GenericObject);
   1585        if (!obj) {
   1586            if (firstObj) {
   1587                PK11_DestroyGenericObjects(firstObj);
   1588            }
   1589            PORT_Free(objectIDs);
   1590            return NULL;
   1591        }
   1592        /* initialize it */
   1593        obj->slot = PK11_ReferenceSlot(slot);
   1594        obj->objectID = objectIDs[i];
   1595        obj->owner = PR_FALSE;
   1596        obj->next = NULL;
   1597        obj->prev = NULL;
   1598 
   1599        /* link it in */
   1600        if (firstObj == NULL) {
   1601            firstObj = obj;
   1602        } else {
   1603            PK11_LinkGenericObject(lastObj, obj);
   1604        }
   1605        lastObj = obj;
   1606    }
   1607    PORT_Free(objectIDs);
   1608    return firstObj;
   1609 }
   1610 
   1611 /*
   1612 * get the Next Object in the list.
   1613 */
   1614 PK11GenericObject *
   1615 PK11_GetNextGenericObject(PK11GenericObject *object)
   1616 {
   1617    return object->next;
   1618 }
   1619 
   1620 PK11GenericObject *
   1621 PK11_GetPrevGenericObject(PK11GenericObject *object)
   1622 {
   1623    return object->prev;
   1624 }
   1625 
   1626 /*
   1627 * Link a single object into a new list.
   1628 * if the object is already in another list, remove it first.
   1629 */
   1630 SECStatus
   1631 PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object)
   1632 {
   1633    PK11_UnlinkGenericObject(object);
   1634    object->prev = list;
   1635    object->next = list->next;
   1636    list->next = object;
   1637    if (object->next != NULL) {
   1638        object->next->prev = object;
   1639    }
   1640    return SECSuccess;
   1641 }
   1642 
   1643 /*
   1644 * remove an object from the list. If the object isn't already in
   1645 * a list unlink becomes a noop.
   1646 */
   1647 SECStatus
   1648 PK11_UnlinkGenericObject(PK11GenericObject *object)
   1649 {
   1650    if (object->prev != NULL) {
   1651        object->prev->next = object->next;
   1652    }
   1653    if (object->next != NULL) {
   1654        object->next->prev = object->prev;
   1655    }
   1656 
   1657    object->next = NULL;
   1658    object->prev = NULL;
   1659    return SECSuccess;
   1660 }
   1661 
   1662 /*
   1663 * This function removes a single object from the list and destroys it.
   1664 * For an already unlinked object there is no difference between
   1665 * PK11_DestroyGenericObject and PK11_DestroyGenericObjects
   1666 */
   1667 SECStatus
   1668 PK11_DestroyGenericObject(PK11GenericObject *object)
   1669 {
   1670    if (object == NULL) {
   1671        return SECSuccess;
   1672    }
   1673 
   1674    PK11_UnlinkGenericObject(object);
   1675    if (object->slot) {
   1676        if (object->owner) {
   1677            PK11_DestroyObject(object->slot, object->objectID);
   1678        }
   1679        PK11_FreeSlot(object->slot);
   1680    }
   1681    PORT_Free(object);
   1682    return SECSuccess;
   1683 }
   1684 
   1685 /*
   1686 * walk down a link list of generic objects destroying them.
   1687 * This will destroy all objects in a list that the object is linked into.
   1688 * (the list is traversed in both directions).
   1689 */
   1690 SECStatus
   1691 PK11_DestroyGenericObjects(PK11GenericObject *objects)
   1692 {
   1693    PK11GenericObject *nextObject;
   1694    PK11GenericObject *prevObject;
   1695 
   1696    if (objects == NULL) {
   1697        return SECSuccess;
   1698    }
   1699 
   1700    nextObject = objects->next;
   1701    prevObject = objects->prev;
   1702 
   1703    /* delete all the objects after it in the list */
   1704    for (; objects; objects = nextObject) {
   1705        nextObject = objects->next;
   1706        PK11_DestroyGenericObject(objects);
   1707    }
   1708    /* delete all the objects before it in the list */
   1709    for (objects = prevObject; objects; objects = prevObject) {
   1710        prevObject = objects->prev;
   1711        PK11_DestroyGenericObject(objects);
   1712    }
   1713    return SECSuccess;
   1714 }
   1715 
   1716 /*
   1717 * Hand Create a new object and return the Generic object for our new object.
   1718 */
   1719 PK11GenericObject *
   1720 pk11_CreateGenericObjectHelper(PK11SlotInfo *slot,
   1721                               const CK_ATTRIBUTE *pTemplate,
   1722                               int count, PRBool token, PRBool owner)
   1723 {
   1724    CK_OBJECT_HANDLE objectID;
   1725    PK11GenericObject *obj;
   1726    CK_RV crv;
   1727 
   1728    PK11_EnterSlotMonitor(slot);
   1729    crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count,
   1730                               token, &objectID);
   1731    PK11_ExitSlotMonitor(slot);
   1732    if (crv != CKR_OK) {
   1733        PORT_SetError(PK11_MapError(crv));
   1734        return NULL;
   1735    }
   1736 
   1737    obj = PORT_New(PK11GenericObject);
   1738    if (!obj) {
   1739        /* error set by PORT_New */
   1740        return NULL;
   1741    }
   1742 
   1743    /* initialize it */
   1744    obj->slot = PK11_ReferenceSlot(slot);
   1745    obj->objectID = objectID;
   1746    obj->owner = owner;
   1747    obj->next = NULL;
   1748    obj->prev = NULL;
   1749    return obj;
   1750 }
   1751 
   1752 /* This is the classic interface. Applications would call this function to
   1753 * create new object that would not be destroyed later. This lead to resource
   1754 * leaks (and thus memory leaks in the PKCS #11 module).  To solve this we have
   1755 * a new interface that automatically marks objects created on the fly to be
   1756 * destroyed later.
   1757 * The old interface is preserved because applications like Mozilla purposefully
   1758 * leak the reference to be found later with PK11_FindGenericObjects. New
   1759 * applications should use the new interface PK11_CreateManagedGenericObject */
   1760 PK11GenericObject *
   1761 PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate,
   1762                         int count, PRBool token)
   1763 {
   1764    return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
   1765                                          PR_FALSE);
   1766 }
   1767 
   1768 /* Use this interface. It will automatically destroy any temporary objects
   1769 * (token = PR_FALSE) when the PK11GenericObject is freed. Permanent objects still
   1770 * need to be destroyed by hand with PK11_DestroyTokenObject.
   1771 */
   1772 PK11GenericObject *
   1773 PK11_CreateManagedGenericObject(PK11SlotInfo *slot,
   1774                                const CK_ATTRIBUTE *pTemplate, int count, PRBool token)
   1775 {
   1776    return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
   1777                                          !token);
   1778 }
   1779 
   1780 CK_OBJECT_HANDLE
   1781 PK11_GetObjectHandle(PK11ObjectType objType, void *objSpec,
   1782                     PK11SlotInfo **slotp)
   1783 {
   1784    CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE;
   1785    PK11SlotInfo *slot = NULL;
   1786 
   1787    switch (objType) {
   1788        case PK11_TypeGeneric:
   1789            slot = ((PK11GenericObject *)objSpec)->slot;
   1790            handle = ((PK11GenericObject *)objSpec)->objectID;
   1791            break;
   1792        case PK11_TypePrivKey:
   1793            slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
   1794            handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
   1795            break;
   1796        case PK11_TypePubKey:
   1797            slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
   1798            handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
   1799            break;
   1800        case PK11_TypeSymKey:
   1801            slot = ((PK11SymKey *)objSpec)->slot;
   1802            handle = ((PK11SymKey *)objSpec)->objectID;
   1803            break;
   1804        case PK11_TypeCert:
   1805            handle = PK11_FindObjectForCert((CERTCertificate *)objSpec, NULL,
   1806                                            &slot);
   1807            break;
   1808        default:
   1809            PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   1810            break;
   1811    }
   1812    if (slotp) {
   1813        *slotp = slot;
   1814    }
   1815    /* paranoia. If the object doesn't have a slot, then it's handle isn't
   1816     * valid either */
   1817    if (slot == NULL) {
   1818        handle = CK_INVALID_HANDLE;
   1819    }
   1820    return handle;
   1821 }
   1822 
   1823 /*
   1824 * Change an attribute on a raw object
   1825 */
   1826 SECStatus
   1827 PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec,
   1828                       CK_ATTRIBUTE_TYPE attrType, SECItem *item)
   1829 {
   1830    PK11SlotInfo *slot = NULL;
   1831    CK_OBJECT_HANDLE handle = 0;
   1832    CK_ATTRIBUTE setTemplate;
   1833    CK_RV crv;
   1834    CK_SESSION_HANDLE rwsession;
   1835 
   1836    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
   1837    if (handle == CK_INVALID_HANDLE) {
   1838        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   1839        return SECFailure;
   1840    }
   1841 
   1842    PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *)item->data, item->len);
   1843    rwsession = PK11_GetRWSession(slot);
   1844    if (rwsession == CK_INVALID_HANDLE) {
   1845        PORT_SetError(SEC_ERROR_BAD_DATA);
   1846        return SECFailure;
   1847    }
   1848    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle,
   1849                                                 &setTemplate, 1);
   1850    PK11_RestoreROSession(slot, rwsession);
   1851    if (crv != CKR_OK) {
   1852        PORT_SetError(PK11_MapError(crv));
   1853        return SECFailure;
   1854    }
   1855    return SECSuccess;
   1856 }
   1857 
   1858 SECStatus
   1859 PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec,
   1860                      CK_ATTRIBUTE_TYPE attrType, SECItem *item)
   1861 {
   1862    PK11SlotInfo *slot = NULL;
   1863    CK_OBJECT_HANDLE handle = 0;
   1864 
   1865    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
   1866    if (handle == CK_INVALID_HANDLE) {
   1867        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   1868        return SECFailure;
   1869    }
   1870 
   1871    return PK11_ReadAttribute(slot, handle, attrType, NULL, item);
   1872 }
   1873 
   1874 SECStatus
   1875 PK11_ReadRawAttributes(PLArenaPool *arena, PK11ObjectType objType, void *objSpec,
   1876                       CK_ATTRIBUTE *pTemplate, unsigned int count)
   1877 {
   1878    PK11SlotInfo *slot = NULL;
   1879    CK_OBJECT_HANDLE handle = 0;
   1880 
   1881    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
   1882    if (handle == CK_INVALID_HANDLE) {
   1883        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   1884        return SECFailure;
   1885    }
   1886    CK_RV crv = PK11_GetAttributes(arena, slot, handle, pTemplate, count);
   1887    if (crv != CKR_OK) {
   1888        PORT_SetError(PK11_MapError(crv));
   1889        return SECFailure;
   1890    }
   1891    return SECSuccess;
   1892 }
   1893 
   1894 SECStatus
   1895 PK11_ReadDistrustAfterAttribute(PK11SlotInfo *slot,
   1896                                CK_OBJECT_HANDLE object,
   1897                                CK_ATTRIBUTE_TYPE type,
   1898                                /* out */ PRBool *distrusted,
   1899                                /* out */ PRTime *time)
   1900 {
   1901    if (!slot || !distrusted || !time) {
   1902        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1903        return SECFailure;
   1904    }
   1905 
   1906    if (type != CKA_NSS_SERVER_DISTRUST_AFTER && type != CKA_NSS_EMAIL_DISTRUST_AFTER) {
   1907        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1908        return SECFailure;
   1909    }
   1910 
   1911    // The CKA_NSS_SERVER_DISTRUST_AFTER and CKA_NSS_EMAIL_DISTRUST_AFTER
   1912    // attributes have either a 13 byte UTCTime value or a 1 byte value
   1913    // (equal to 0) indicating that no distrust after date is set.
   1914    unsigned char buf[13] = { 0 };
   1915    CK_ATTRIBUTE attr = { .type = type, .pValue = buf, .ulValueLen = sizeof buf };
   1916    CK_RV crv;
   1917 
   1918    PK11_EnterSlotMonitor(slot);
   1919    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, object, &attr, 1);
   1920    PK11_ExitSlotMonitor(slot);
   1921    if (crv != CKR_OK) {
   1922        PORT_SetError(PK11_MapError(crv));
   1923        return SECFailure;
   1924    }
   1925 
   1926    if (attr.ulValueLen == 1 && buf[0] == 0) {
   1927        // The distrust after date is not set.
   1928        *distrusted = PR_FALSE;
   1929        return SECSuccess;
   1930    }
   1931 
   1932    if (attr.ulValueLen != sizeof buf) {
   1933        // Ensure the date is encoded in the expected 13 byte format.
   1934        PORT_SetError(SEC_ERROR_INVALID_TIME);
   1935        return SECFailure;
   1936    }
   1937 
   1938    *distrusted = PR_TRUE;
   1939    SECItem item = { siUTCTime, buf, sizeof buf };
   1940    return DER_UTCTimeToTime(time, &item);
   1941 }
   1942 
   1943 /*
   1944 * return the object handle that matches the template
   1945 */
   1946 CK_OBJECT_HANDLE
   1947 pk11_FindObjectByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *theTemplate, size_t tsize)
   1948 {
   1949    CK_OBJECT_HANDLE object;
   1950    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
   1951    CK_ULONG objectCount;
   1952 
   1953    /*
   1954     * issue the find
   1955     */
   1956    PK11_EnterSlotMonitor(slot);
   1957    if (slot->session != CK_INVALID_HANDLE) {
   1958        crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
   1959                                                   theTemplate, tsize);
   1960    }
   1961    if (crv != CKR_OK) {
   1962        PK11_ExitSlotMonitor(slot);
   1963        PORT_SetError(PK11_MapError(crv));
   1964        return CK_INVALID_HANDLE;
   1965    }
   1966 
   1967    crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, &object, 1, &objectCount);
   1968    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
   1969    PK11_ExitSlotMonitor(slot);
   1970    if ((crv != CKR_OK) || (objectCount < 1)) {
   1971        /* shouldn't use SSL_ERROR... here */
   1972        PORT_SetError(crv != CKR_OK ? PK11_MapError(crv) : SSL_ERROR_NO_CERTIFICATE);
   1973        return CK_INVALID_HANDLE;
   1974    }
   1975 
   1976    /* blow up if the PKCS #11 module returns us and invalid object handle */
   1977    PORT_Assert(object != CK_INVALID_HANDLE);
   1978    return object;
   1979 }
   1980 
   1981 /*
   1982 * return all the object handles that matches the template
   1983 */
   1984 CK_OBJECT_HANDLE *
   1985 pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
   1986                           size_t templCount, int *object_count)
   1987 {
   1988    CK_OBJECT_HANDLE *objID = NULL;
   1989    CK_ULONG returned_count = 0;
   1990    PRBool owner = PR_TRUE;
   1991    CK_SESSION_HANDLE session;
   1992    PRBool haslock = PR_FALSE;
   1993    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
   1994 
   1995    session = pk11_GetNewSession(slot, &owner);
   1996    haslock = (!owner || !(slot->isThreadSafe));
   1997    if (haslock) {
   1998        PK11_EnterSlotMonitor(slot);
   1999    }
   2000    if (session != CK_INVALID_HANDLE) {
   2001        crv = PK11_GETTAB(slot)->C_FindObjectsInit(session,
   2002                                                   findTemplate, templCount);
   2003    }
   2004    if (crv != CKR_OK) {
   2005        if (haslock)
   2006            PK11_ExitSlotMonitor(slot);
   2007        pk11_CloseSession(slot, session, owner);
   2008        PORT_SetError(PK11_MapError(crv));
   2009        *object_count = -1;
   2010        return NULL;
   2011    }
   2012 
   2013    /*
   2014     * collect all the Matching Objects
   2015     */
   2016    do {
   2017        CK_OBJECT_HANDLE *oldObjID = objID;
   2018 
   2019        if (objID == NULL) {
   2020            objID = (CK_OBJECT_HANDLE *)PORT_Alloc(sizeof(CK_OBJECT_HANDLE) *
   2021                                                   (*object_count + PK11_SEARCH_CHUNKSIZE));
   2022        } else {
   2023            objID = (CK_OBJECT_HANDLE *)PORT_Realloc(objID,
   2024                                                     sizeof(CK_OBJECT_HANDLE) * (*object_count + PK11_SEARCH_CHUNKSIZE));
   2025        }
   2026 
   2027        if (objID == NULL) {
   2028            if (oldObjID)
   2029                PORT_Free(oldObjID);
   2030            break;
   2031        }
   2032        crv = PK11_GETTAB(slot)->C_FindObjects(session,
   2033                                               &objID[*object_count], PK11_SEARCH_CHUNKSIZE, &returned_count);
   2034        if (crv != CKR_OK) {
   2035            PORT_SetError(PK11_MapError(crv));
   2036            PORT_Free(objID);
   2037            objID = NULL;
   2038            break;
   2039        }
   2040        *object_count += returned_count;
   2041    } while (returned_count == PK11_SEARCH_CHUNKSIZE);
   2042 
   2043    PK11_GETTAB(slot)->C_FindObjectsFinal(session);
   2044    if (haslock) {
   2045        PK11_ExitSlotMonitor(slot);
   2046    }
   2047    pk11_CloseSession(slot, session, owner);
   2048 
   2049    if (objID && (*object_count == 0)) {
   2050        PORT_Free(objID);
   2051        return NULL;
   2052    }
   2053    if (objID == NULL)
   2054        *object_count = -1;
   2055    return objID;
   2056 }
   2057 
   2058 SECStatus
   2059 PK11_FindRawCertsWithSubject(PK11SlotInfo *slot, SECItem *derSubject,
   2060                             CERTCertificateList **results)
   2061 {
   2062    if (!slot || !derSubject || !results) {
   2063        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2064        return SECFailure;
   2065    }
   2066    *results = NULL;
   2067 
   2068    // derSubject->data may be null. If so, derSubject->len must be 0.
   2069    if (!derSubject->data && derSubject->len != 0) {
   2070        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2071        return SECFailure;
   2072    }
   2073 
   2074    CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509;
   2075    CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
   2076    CK_ATTRIBUTE subjectTemplate[] = {
   2077        { CKA_CERTIFICATE_TYPE, &ckc_x_509, sizeof(ckc_x_509) },
   2078        { CKA_CLASS, &cko_certificate, sizeof(cko_certificate) },
   2079        { CKA_SUBJECT, derSubject->data, derSubject->len },
   2080    };
   2081    const size_t templateCount = sizeof(subjectTemplate) / sizeof(subjectTemplate[0]);
   2082    int handleCount = 0;
   2083    CK_OBJECT_HANDLE *handles =
   2084        pk11_FindObjectsByTemplate(slot, subjectTemplate, templateCount,
   2085                                   &handleCount);
   2086    if (!handles) {
   2087        // pk11_FindObjectsByTemplate indicates there was an error by setting
   2088        // handleCount to -1 (and it has set an error with PORT_SetError).
   2089        if (handleCount == -1) {
   2090            return SECFailure;
   2091        }
   2092        return SECSuccess;
   2093    }
   2094    PORT_Assert(handleCount > 0);
   2095    if (handleCount <= 0) {
   2096        PORT_Free(handles);
   2097        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   2098        return SECFailure;
   2099    }
   2100    if (handleCount > INT_MAX / sizeof(SECItem)) {
   2101        PORT_Free(handles);
   2102        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   2103        return SECFailure;
   2104    }
   2105    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   2106    if (!arena) {
   2107        PORT_Free(handles);
   2108        return SECFailure;
   2109    }
   2110    CERTCertificateList *rawCertificates =
   2111        PORT_ArenaNew(arena, CERTCertificateList);
   2112    if (!rawCertificates) {
   2113        PORT_Free(handles);
   2114        PORT_FreeArena(arena, PR_FALSE);
   2115        return SECFailure;
   2116    }
   2117    rawCertificates->arena = arena;
   2118    rawCertificates->certs = PORT_ArenaNewArray(arena, SECItem, handleCount);
   2119    if (!rawCertificates->certs) {
   2120        PORT_Free(handles);
   2121        PORT_FreeArena(arena, PR_FALSE);
   2122        return SECFailure;
   2123    }
   2124    rawCertificates->len = handleCount;
   2125    int handleIndex;
   2126    for (handleIndex = 0; handleIndex < handleCount; handleIndex++) {
   2127        SECStatus rv =
   2128            PK11_ReadAttribute(slot, handles[handleIndex], CKA_VALUE, arena,
   2129                               &rawCertificates->certs[handleIndex]);
   2130        if (rv != SECSuccess) {
   2131            PORT_Free(handles);
   2132            PORT_FreeArena(arena, PR_FALSE);
   2133            return SECFailure;
   2134        }
   2135        if (!rawCertificates->certs[handleIndex].data) {
   2136            PORT_Free(handles);
   2137            PORT_FreeArena(arena, PR_FALSE);
   2138            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   2139            return SECFailure;
   2140        }
   2141    }
   2142    PORT_Free(handles);
   2143    *results = rawCertificates;
   2144    return SECSuccess;
   2145 }
   2146 
   2147 /*
   2148 * given a PKCS #11 object, match it's peer based on the KeyID. searchID
   2149 * is typically a privateKey or a certificate while the peer is the opposite
   2150 */
   2151 CK_OBJECT_HANDLE
   2152 PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,
   2153               CK_OBJECT_CLASS matchclass)
   2154 {
   2155    CK_ATTRIBUTE theTemplate[] = {
   2156        { CKA_ID, NULL, 0 },
   2157        { CKA_CLASS, NULL, 0 }
   2158    };
   2159    /* if you change the array, change the variable below as well */
   2160    CK_ATTRIBUTE *keyclass = &theTemplate[1];
   2161    const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
   2162    /* if you change the array, change the variable below as well */
   2163    CK_OBJECT_HANDLE peerID;
   2164    PORTCheapArenaPool tmpArena;
   2165    CK_RV crv;
   2166 
   2167    /* now we need to create space for the public key */
   2168    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
   2169 
   2170    crv = PK11_GetAttributes(&tmpArena.arena, slot, searchID, theTemplate, tsize);
   2171    if (crv != CKR_OK) {
   2172        PORT_DestroyCheapArena(&tmpArena);
   2173        PORT_SetError(PK11_MapError(crv));
   2174        return CK_INVALID_HANDLE;
   2175    }
   2176 
   2177    if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
   2178        PORT_DestroyCheapArena(&tmpArena);
   2179        if (matchclass == CKO_CERTIFICATE) {
   2180            PORT_SetError(SEC_ERROR_BAD_KEY);
   2181        } else {
   2182            PORT_SetError(SEC_ERROR_NO_KEY);
   2183        }
   2184        return CK_INVALID_HANDLE;
   2185    }
   2186 
   2187    /*
   2188     * issue the find
   2189     */
   2190    *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;
   2191 
   2192    peerID = pk11_FindObjectByTemplate(slot, theTemplate, tsize);
   2193    PORT_DestroyCheapArena(&tmpArena);
   2194 
   2195    return peerID;
   2196 }
   2197 
   2198 /*
   2199 * count the number of objects that match the template.
   2200 */
   2201 int
   2202 PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
   2203                      int templCount)
   2204 {
   2205    CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE];
   2206    int object_count = 0;
   2207    CK_ULONG returned_count = 0;
   2208    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
   2209 
   2210    PK11_EnterSlotMonitor(slot);
   2211    if (slot->session != CK_INVALID_HANDLE) {
   2212        crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
   2213                                                   findTemplate, templCount);
   2214    }
   2215    if (crv != CKR_OK) {
   2216        PK11_ExitSlotMonitor(slot);
   2217        PORT_SetError(PK11_MapError(crv));
   2218        return object_count;
   2219    }
   2220 
   2221    /*
   2222     * collect all the Matching Objects
   2223     */
   2224    do {
   2225        crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID,
   2226                                               PK11_SEARCH_CHUNKSIZE,
   2227                                               &returned_count);
   2228        if (crv != CKR_OK) {
   2229            PORT_SetError(PK11_MapError(crv));
   2230            break;
   2231        }
   2232        object_count += returned_count;
   2233    } while (returned_count == PK11_SEARCH_CHUNKSIZE);
   2234 
   2235    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
   2236    PK11_ExitSlotMonitor(slot);
   2237    return object_count;
   2238 }
   2239 
   2240 /*
   2241 * Traverse all the objects in a given slot.
   2242 */
   2243 SECStatus
   2244 PK11_TraverseSlot(PK11SlotInfo *slot, void *arg)
   2245 {
   2246    int i;
   2247    CK_OBJECT_HANDLE *objID = NULL;
   2248    int object_count = 0;
   2249    pk11TraverseSlot *slotcb = (pk11TraverseSlot *)arg;
   2250 
   2251    objID = pk11_FindObjectsByTemplate(slot, slotcb->findTemplate,
   2252                                       slotcb->templateCount, &object_count);
   2253 
   2254    /*Actually this isn't a failure... there just were no objs to be found*/
   2255    if (object_count == 0) {
   2256        return SECSuccess;
   2257    }
   2258 
   2259    if (objID == NULL) {
   2260        return SECFailure;
   2261    }
   2262 
   2263    for (i = 0; i < object_count; i++) {
   2264        (*slotcb->callback)(slot, objID[i], slotcb->callbackArg);
   2265    }
   2266    PORT_Free(objID);
   2267    return SECSuccess;
   2268 }
   2269 
   2270 /*
   2271 * Traverse all the objects in all slots.
   2272 */
   2273 SECStatus
   2274 pk11_TraverseAllSlots(SECStatus (*callback)(PK11SlotInfo *, void *),
   2275                      void *arg, PRBool forceLogin, void *wincx)
   2276 {
   2277    PK11SlotList *list;
   2278    PK11SlotListElement *le;
   2279    SECStatus rv;
   2280 
   2281    /* get them all! */
   2282    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, wincx);
   2283    if (list == NULL)
   2284        return SECFailure;
   2285 
   2286    /* look at each slot and authenticate as necessary */
   2287    for (le = list->head; le; le = le->next) {
   2288        if (forceLogin) {
   2289            rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx);
   2290            if (rv != SECSuccess) {
   2291                continue;
   2292            }
   2293        }
   2294        if (callback) {
   2295            (*callback)(le->slot, arg);
   2296        }
   2297    }
   2298 
   2299    PK11_FreeSlotList(list);
   2300 
   2301    return SECSuccess;
   2302 }
   2303 
   2304 CK_OBJECT_HANDLE *
   2305 PK11_FindObjectsFromNickname(char *nickname, PK11SlotInfo **slotptr,
   2306                             CK_OBJECT_CLASS objclass, int *returnCount, void *wincx)
   2307 {
   2308    char *tokenName;
   2309    char *delimit;
   2310    PK11SlotInfo *slot;
   2311    CK_OBJECT_HANDLE *objID;
   2312    CK_ATTRIBUTE findTemplate[] = {
   2313        { CKA_LABEL, NULL, 0 },
   2314        { CKA_CLASS, NULL, 0 },
   2315    };
   2316    const size_t findCount = sizeof(findTemplate) / sizeof(findTemplate[0]);
   2317    SECStatus rv;
   2318    PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass));
   2319 
   2320    *slotptr = slot = NULL;
   2321    *returnCount = 0;
   2322    /* first find the slot associated with this nickname */
   2323    if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
   2324        int len = delimit - nickname;
   2325        tokenName = (char *)PORT_Alloc(len + 1);
   2326        if (!tokenName) {
   2327            return CK_INVALID_HANDLE;
   2328        }
   2329        PORT_Memcpy(tokenName, nickname, len);
   2330        tokenName[len] = 0;
   2331 
   2332        slot = *slotptr = PK11_FindSlotByName(tokenName);
   2333        PORT_Free(tokenName);
   2334        /* if we couldn't find a slot, assume the nickname is an internal cert
   2335         * with no proceding slot name */
   2336        if (slot == NULL) {
   2337            slot = *slotptr = PK11_GetInternalKeySlot();
   2338        } else {
   2339            nickname = delimit + 1;
   2340        }
   2341    } else {
   2342        *slotptr = slot = PK11_GetInternalKeySlot();
   2343    }
   2344    if (slot == NULL) {
   2345        return CK_INVALID_HANDLE;
   2346    }
   2347 
   2348    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
   2349    if (rv != SECSuccess) {
   2350        PK11_FreeSlot(slot);
   2351        *slotptr = NULL;
   2352        return CK_INVALID_HANDLE;
   2353    }
   2354 
   2355    findTemplate[0].pValue = nickname;
   2356    findTemplate[0].ulValueLen = PORT_Strlen(nickname);
   2357    objID = pk11_FindObjectsByTemplate(slot, findTemplate, findCount, returnCount);
   2358    if (objID == NULL) {
   2359        /* PKCS #11 isn't clear on whether or not the NULL is
   2360         * stored in the template.... try the find again with the
   2361         * full null terminated string. */
   2362        findTemplate[0].ulValueLen += 1;
   2363        objID = pk11_FindObjectsByTemplate(slot, findTemplate, findCount,
   2364                                           returnCount);
   2365        if (objID == NULL) {
   2366            /* Well that's the best we can do. It's just not here */
   2367            /* what about faked nicknames? */
   2368            PK11_FreeSlot(slot);
   2369            *slotptr = NULL;
   2370            *returnCount = 0;
   2371        }
   2372    }
   2373 
   2374    return objID;
   2375 }
   2376 
   2377 SECItem *
   2378 pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
   2379 {
   2380    CK_ATTRIBUTE theTemplate[] = {
   2381        { CKA_ID, NULL, 0 },
   2382    };
   2383    int tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
   2384    CK_RV crv;
   2385    SECItem *item;
   2386 
   2387    item = SECITEM_AllocItem(NULL, NULL, 0);
   2388 
   2389    if (item == NULL) {
   2390        return NULL;
   2391    }
   2392 
   2393    crv = PK11_GetAttributes(NULL, slot, handle, theTemplate, tsize);
   2394    if (crv != CKR_OK) {
   2395        SECITEM_FreeItem(item, PR_TRUE);
   2396        PORT_SetError(PK11_MapError(crv));
   2397        return NULL;
   2398    }
   2399 
   2400    item->data = (unsigned char *)theTemplate[0].pValue;
   2401    item->len = theTemplate[0].ulValueLen;
   2402 
   2403    return item;
   2404 }
   2405 
   2406 PRBool
   2407 PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec)
   2408 {
   2409    PK11SlotInfo *slot = NULL;
   2410    CK_OBJECT_HANDLE handle = 0;
   2411 
   2412    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
   2413    if (handle == CK_INVALID_HANDLE) {
   2414        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   2415        return PR_FALSE;
   2416    }
   2417    return pk11slot_GetFIPSStatus(slot, slot->session, handle,
   2418                                  CKT_NSS_OBJECT_CHECK);
   2419 }