tor-browser

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

pkcs11u.c (85233B)


      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 * Internal PKCS #11 functions. Should only be called by pkcs11.c
      6 */
      7 #include "pkcs11.h"
      8 #include "pkcs11i.h"
      9 #include "lowkeyi.h"
     10 #include "secasn1.h"
     11 #include "blapi.h"
     12 #include "secerr.h"
     13 #include "prnetdb.h" /* for PR_ntohl */
     14 #include "sftkdb.h"
     15 #include "softoken.h"
     16 #include "secoid.h"
     17 #include "softkver.h"
     18 
     19 #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS)
     20 /* this file should be supplied by the vendor and include all the
     21 * algorithms which have Algorithm certs and have been reviewed by
     22 * the lab. A blank file is included for the base so that FIPS mode
     23 * will still be compiled and run, but FIPS indicators will always
     24 * return PR_FALSE
     25 */
     26 #include "fips_algorithms.h"
     27 #define NSS_HAS_FIPS_INDICATORS 1
     28 #endif
     29 
     30 /*
     31 * ******************** Error mapping *******************************
     32 */
     33 /*
     34 * map all the SEC_ERROR_xxx error codes that may be returned by freebl
     35 * functions to CKR_xxx.  return CKR_DEVICE_ERROR by default for backward
     36 * compatibility.
     37 */
     38 CK_RV
     39 sftk_MapCryptError(int error)
     40 {
     41    switch (error) {
     42        case SEC_ERROR_INVALID_ARGS:
     43        case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */
     44            return CKR_ARGUMENTS_BAD;
     45        case SEC_ERROR_INPUT_LEN:
     46            return CKR_DATA_LEN_RANGE;
     47        case SEC_ERROR_OUTPUT_LEN:
     48            return CKR_BUFFER_TOO_SMALL;
     49        case SEC_ERROR_LIBRARY_FAILURE:
     50            return CKR_GENERAL_ERROR;
     51        case SEC_ERROR_NO_MEMORY:
     52            return CKR_HOST_MEMORY;
     53        case SEC_ERROR_BAD_SIGNATURE:
     54            return CKR_SIGNATURE_INVALID;
     55        case SEC_ERROR_INVALID_KEY:
     56            return CKR_KEY_SIZE_RANGE;
     57        case SEC_ERROR_BAD_KEY:        /* an EC public key that fails validation */
     58            return CKR_KEY_SIZE_RANGE; /* the closest error code */
     59        case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
     60            return CKR_TEMPLATE_INCONSISTENT;
     61        case SEC_ERROR_UNSUPPORTED_KEYALG:
     62            return CKR_MECHANISM_INVALID;
     63        case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
     64            return CKR_DOMAIN_PARAMS_INVALID;
     65        /* key pair generation failed after max number of attempts */
     66        case SEC_ERROR_NEED_RANDOM:
     67            return CKR_FUNCTION_FAILED;
     68    }
     69    return CKR_DEVICE_ERROR;
     70 }
     71 
     72 /*
     73 * functions which adjust the mapping based on different contexts
     74 * (Decrypt or Verify).
     75 */
     76 
     77 /* used by Decrypt and UnwrapKey (indirectly) and Decrypt message */
     78 CK_RV
     79 sftk_MapDecryptError(int error)
     80 {
     81    switch (error) {
     82        /* usually a padding error, or aead tag mismatch */
     83        case SEC_ERROR_BAD_DATA:
     84            return CKR_ENCRYPTED_DATA_INVALID;
     85        default:
     86            return sftk_MapCryptError(error);
     87    }
     88 }
     89 
     90 /*
     91 * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for
     92 * backward compatibilty.
     93 */
     94 CK_RV
     95 sftk_MapVerifyError(int error)
     96 {
     97    CK_RV crv = sftk_MapCryptError(error);
     98    if (crv == CKR_DEVICE_ERROR)
     99        crv = CKR_SIGNATURE_INVALID;
    100    return crv;
    101 }
    102 
    103 /*
    104 * ******************** Attribute Utilities *******************************
    105 */
    106 
    107 /*
    108 * create a new attribute with type, value, and length. Space is allocated
    109 * to hold value.
    110 */
    111 static SFTKAttribute *
    112 sftk_NewAttribute(SFTKObject *object,
    113                  CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len)
    114 {
    115    SFTKAttribute *attribute;
    116 
    117    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
    118    int index;
    119 
    120    if (so == NULL) {
    121        /* allocate new attribute in a buffer */
    122        PORT_Assert(0);
    123        return NULL;
    124    }
    125    /*
    126     * We attempt to keep down contention on Malloc and Arena locks by
    127     * limiting the number of these calls on high traversed paths. This
    128     * is done for attributes by 'allocating' them from a pool already
    129     * allocated by the parent object.
    130     */
    131    PZ_Lock(so->attributeLock);
    132    index = so->nextAttr++;
    133    PZ_Unlock(so->attributeLock);
    134    PORT_Assert(index < MAX_OBJS_ATTRS);
    135    if (index >= MAX_OBJS_ATTRS)
    136        return NULL;
    137 
    138    attribute = &so->attrList[index];
    139    attribute->attrib.type = type;
    140    attribute->freeAttr = PR_FALSE;
    141    attribute->freeData = PR_FALSE;
    142    if (value) {
    143        if (len <= ATTR_SPACE) {
    144            attribute->attrib.pValue = attribute->space;
    145        } else {
    146            attribute->attrib.pValue = PORT_Alloc(len);
    147            attribute->freeData = PR_TRUE;
    148        }
    149        if (attribute->attrib.pValue == NULL) {
    150            return NULL;
    151        }
    152        PORT_Memcpy(attribute->attrib.pValue, value, len);
    153        attribute->attrib.ulValueLen = len;
    154    } else {
    155        attribute->attrib.pValue = NULL;
    156        attribute->attrib.ulValueLen = 0;
    157    }
    158    attribute->attrib.type = type;
    159    attribute->handle = type;
    160    attribute->next = attribute->prev = NULL;
    161    return attribute;
    162 }
    163 
    164 /*
    165 * Free up all the memory associated with an attribute. Reference count
    166 * must be zero to call this.
    167 */
    168 static void
    169 sftk_DestroyAttribute(SFTKAttribute *attribute)
    170 {
    171    if (attribute->attrib.pValue) {
    172        /* clear out the data in the attribute value... it may have been
    173         * sensitive data */
    174        PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen);
    175        if (attribute->freeData) {
    176            PORT_Free(attribute->attrib.pValue);
    177            attribute->attrib.pValue = NULL;
    178            attribute->freeData = PR_FALSE;
    179        }
    180    }
    181    if (attribute->freeAttr) {
    182        PORT_Free(attribute);
    183    }
    184 }
    185 
    186 /*
    187 * release a reference to an attribute structure
    188 */
    189 void
    190 sftk_FreeAttribute(SFTKAttribute *attribute)
    191 {
    192    if (attribute && attribute->freeAttr) {
    193        sftk_DestroyAttribute(attribute);
    194        return;
    195    }
    196 }
    197 
    198 static SFTKAttribute *
    199 sftk_FindTokenAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
    200 {
    201    SFTKAttribute *myattribute = NULL;
    202    SFTKDBHandle *dbHandle = NULL;
    203    CK_RV crv = CKR_HOST_MEMORY;
    204 
    205    myattribute = (SFTKAttribute *)PORT_Alloc(sizeof(SFTKAttribute));
    206    if (myattribute == NULL) {
    207        goto loser;
    208    }
    209 
    210    dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
    211 
    212    myattribute->handle = type;
    213    myattribute->attrib.type = type;
    214    myattribute->attrib.pValue = myattribute->space;
    215    myattribute->attrib.ulValueLen = ATTR_SPACE;
    216    myattribute->next = myattribute->prev = NULL;
    217    myattribute->freeAttr = PR_TRUE;
    218    myattribute->freeData = PR_FALSE;
    219 
    220    crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
    221                                   &myattribute->attrib, 1);
    222 
    223    /* attribute is bigger than our attribute space buffer, malloc it */
    224    if (crv == CKR_BUFFER_TOO_SMALL) {
    225        myattribute->attrib.pValue = NULL;
    226        crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
    227                                       &myattribute->attrib, 1);
    228        if (crv != CKR_OK) {
    229            goto loser;
    230        }
    231        myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen);
    232        if (myattribute->attrib.pValue == NULL) {
    233            crv = CKR_HOST_MEMORY;
    234            goto loser;
    235        }
    236        myattribute->freeData = PR_TRUE;
    237        crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
    238                                       &myattribute->attrib, 1);
    239    }
    240 loser:
    241    if (dbHandle) {
    242        sftk_freeDB(dbHandle);
    243    }
    244    if (crv != CKR_OK) {
    245        if (myattribute) {
    246            myattribute->attrib.ulValueLen = 0;
    247            sftk_FreeAttribute(myattribute);
    248            myattribute = NULL;
    249        }
    250    }
    251    return myattribute;
    252 }
    253 
    254 /*
    255 * look up and attribute structure from a type and Object structure.
    256 * The returned attribute is referenced and needs to be freed when
    257 * it is no longer needed.
    258 */
    259 SFTKAttribute *
    260 sftk_FindAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
    261 {
    262    SFTKAttribute *attribute;
    263    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
    264 
    265    /* validation flags are stored as FIPS indicators */
    266    if (type == CKA_OBJECT_VALIDATION_FLAGS) {
    267        return &object->validation_attribute;
    268    }
    269 
    270    if (sessObject == NULL) {
    271        return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object), type);
    272    }
    273 
    274    PZ_Lock(sessObject->attributeLock);
    275    sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize);
    276    PZ_Unlock(sessObject->attributeLock);
    277 
    278    return (attribute);
    279 }
    280 
    281 /*
    282 * Take a buffer and it's length and return it's true size in bits;
    283 */
    284 unsigned int
    285 sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
    286 {
    287    unsigned int size = bufLen * 8;
    288    unsigned int i;
    289 
    290    /* Get the real length in bytes */
    291    for (i = 0; i < bufLen; i++) {
    292        unsigned char c = *buf++;
    293        if (c != 0) {
    294            unsigned char m;
    295            for (m = 0x80; m > 0; m = m >> 1) {
    296                if ((c & m) != 0) {
    297                    break;
    298                }
    299                size--;
    300            }
    301            break;
    302        }
    303        size -= 8;
    304    }
    305    return size;
    306 }
    307 
    308 /*
    309 * Constrain a big num attribute. to size and padding
    310 * minLength means length of the object must be greater than equal to minLength
    311 * maxLength means length of the object must be less than equal to maxLength
    312 * minMultiple means that object length mod minMultiple must equal 0.
    313 * all input sizes are in bits.
    314 * if any constraint is '0' that constraint is not checked.
    315 */
    316 CK_RV
    317 sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    318                        int minLength, int maxLength, int minMultiple)
    319 {
    320    SFTKAttribute *attribute;
    321    int size;
    322    unsigned char *ptr;
    323 
    324    attribute = sftk_FindAttribute(object, type);
    325    if (!attribute) {
    326        return CKR_TEMPLATE_INCOMPLETE;
    327    }
    328    ptr = (unsigned char *)attribute->attrib.pValue;
    329    if (ptr == NULL) {
    330        sftk_FreeAttribute(attribute);
    331        return CKR_ATTRIBUTE_VALUE_INVALID;
    332    }
    333    size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
    334    sftk_FreeAttribute(attribute);
    335 
    336    if ((minLength != 0) && (size < minLength)) {
    337        return CKR_ATTRIBUTE_VALUE_INVALID;
    338    }
    339    if ((maxLength != 0) && (size > maxLength)) {
    340        return CKR_ATTRIBUTE_VALUE_INVALID;
    341    }
    342    if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
    343        return CKR_ATTRIBUTE_VALUE_INVALID;
    344    }
    345    return CKR_OK;
    346 }
    347 
    348 PRBool
    349 sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
    350 {
    351    CK_ATTRIBUTE template;
    352    CK_RV crv;
    353    SFTKDBHandle *dbHandle;
    354 
    355    dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
    356    template.type = type;
    357    template.pValue = NULL;
    358    template.ulValueLen = 0;
    359 
    360    crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1);
    361    sftk_freeDB(dbHandle);
    362 
    363    /* attribute is bigger than our attribute space buffer, malloc it */
    364    return (crv == CKR_OK) ? PR_TRUE : PR_FALSE;
    365 }
    366 
    367 /*
    368 * return true if object has attribute
    369 */
    370 PRBool
    371 sftk_hasAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
    372 {
    373    SFTKAttribute *attribute;
    374    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
    375 
    376    if (sessObject == NULL) {
    377        return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type);
    378    }
    379 
    380    PZ_Lock(sessObject->attributeLock);
    381    sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize);
    382    PZ_Unlock(sessObject->attributeLock);
    383 
    384    return (PRBool)(attribute != NULL);
    385 }
    386 
    387 /*
    388 * add an attribute to an object
    389 */
    390 static void
    391 sftk_AddAttribute(SFTKObject *object, SFTKAttribute *attribute)
    392 {
    393    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
    394 
    395    if (sessObject == NULL)
    396        return;
    397    PZ_Lock(sessObject->attributeLock);
    398    sftkqueue_add(attribute, attribute->handle,
    399                  sessObject->head, sessObject->hashSize);
    400    PZ_Unlock(sessObject->attributeLock);
    401 }
    402 
    403 /*
    404 * copy an unsigned attribute into a SECItem. Secitem is allocated in
    405 * the specified arena.
    406 */
    407 CK_RV
    408 sftk_Attribute2SSecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object,
    409                        CK_ATTRIBUTE_TYPE type)
    410 {
    411    SFTKAttribute *attribute;
    412 
    413    item->data = NULL;
    414 
    415    attribute = sftk_FindAttribute(object, type);
    416    if (attribute == NULL)
    417        return CKR_TEMPLATE_INCOMPLETE;
    418 
    419    (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
    420    if (item->data == NULL) {
    421        sftk_FreeAttribute(attribute);
    422        return CKR_HOST_MEMORY;
    423    }
    424    PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
    425    sftk_FreeAttribute(attribute);
    426    return CKR_OK;
    427 }
    428 
    429 /*
    430 * fetch multiple attributes into  SECItems. Secitem data is allocated in
    431 * the specified arena.
    432 */
    433 CK_RV
    434 sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object,
    435                               SFTKItemTemplate *itemTemplate, int itemTemplateCount)
    436 {
    437 
    438    CK_RV crv = CKR_OK;
    439    CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE];
    440    CK_ATTRIBUTE *template;
    441    SFTKTokenObject *tokObject;
    442    SFTKDBHandle *dbHandle = NULL;
    443    int i;
    444 
    445    tokObject = sftk_narrowToTokenObject(object);
    446 
    447    /* session objects, just loop through the list */
    448    if (tokObject == NULL) {
    449        for (i = 0; i < itemTemplateCount; i++) {
    450            crv = sftk_Attribute2SecItem(arena, itemTemplate[i].item, object,
    451                                         itemTemplate[i].type);
    452            if (crv != CKR_OK) {
    453                return crv;
    454            }
    455        }
    456        return CKR_OK;
    457    }
    458 
    459    /* don't do any work if none is required */
    460    if (itemTemplateCount == 0) {
    461        return CKR_OK;
    462    }
    463 
    464    /* don't allocate the template unless we need it */
    465    if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) {
    466        template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount);
    467    } else {
    468        template = templateSpace;
    469    }
    470 
    471    if (template == NULL) {
    472        crv = CKR_HOST_MEMORY;
    473        goto loser;
    474    }
    475 
    476    dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
    477    if (dbHandle == NULL) {
    478        crv = CKR_OBJECT_HANDLE_INVALID;
    479        goto loser;
    480    }
    481 
    482    /* set up the PKCS #11 template */
    483    for (i = 0; i < itemTemplateCount; i++) {
    484        template[i].type = itemTemplate[i].type;
    485        template[i].pValue = NULL;
    486        template[i].ulValueLen = 0;
    487    }
    488 
    489    /* fetch the attribute lengths */
    490    crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
    491                                   template, itemTemplateCount);
    492    if (crv != CKR_OK) {
    493        goto loser;
    494    }
    495 
    496    /* allocate space for the attributes */
    497    for (i = 0; i < itemTemplateCount; i++) {
    498        template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen);
    499        if (template[i].pValue == NULL) {
    500            crv = CKR_HOST_MEMORY;
    501            goto loser;
    502        }
    503    }
    504 
    505    /* fetch the attributes */
    506    crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
    507                                   template, itemTemplateCount);
    508    if (crv != CKR_OK) {
    509        goto loser;
    510    }
    511 
    512    /* Fill in the items */
    513    for (i = 0; i < itemTemplateCount; i++) {
    514        itemTemplate[i].item->data = template[i].pValue;
    515        itemTemplate[i].item->len = template[i].ulValueLen;
    516    }
    517 
    518 loser:
    519    if (template != templateSpace) {
    520        PORT_Free(template);
    521    }
    522    if (dbHandle) {
    523        sftk_freeDB(dbHandle);
    524    }
    525 
    526    return crv;
    527 }
    528 
    529 /*
    530 * delete an attribute from an object
    531 */
    532 static void
    533 sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
    534 {
    535    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
    536 
    537    if (sessObject == NULL) {
    538        return;
    539    }
    540    PZ_Lock(sessObject->attributeLock);
    541    if (sftkqueue_is_queued(attribute, attribute->handle,
    542                            sessObject->head, sessObject->hashSize)) {
    543        sftkqueue_delete(attribute, attribute->handle,
    544                         sessObject->head, sessObject->hashSize);
    545    }
    546    PZ_Unlock(sessObject->attributeLock);
    547 }
    548 
    549 /*
    550 * this is only valid for CK_BBOOL type attributes. Return the state
    551 * of that attribute.
    552 */
    553 PRBool
    554 sftk_isTrue(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
    555 {
    556    SFTKAttribute *attribute;
    557    PRBool tok = PR_FALSE;
    558 
    559    attribute = sftk_FindAttribute(object, type);
    560    if (attribute == NULL) {
    561        return PR_FALSE;
    562    }
    563    tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
    564    sftk_FreeAttribute(attribute);
    565 
    566    return tok;
    567 }
    568 
    569 /*
    570 * force an attribute to null.
    571 * this is for sensitive keys which are stored in the database, we don't
    572 * want to keep this info around in memory in the clear.
    573 */
    574 void
    575 sftk_nullAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
    576 {
    577    SFTKAttribute *attribute;
    578 
    579    attribute = sftk_FindAttribute(object, type);
    580    if (attribute == NULL)
    581        return;
    582 
    583    if (attribute->attrib.pValue != NULL) {
    584        PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen);
    585        if (attribute->freeData) {
    586            PORT_Free(attribute->attrib.pValue);
    587        }
    588        attribute->freeData = PR_FALSE;
    589        attribute->attrib.pValue = NULL;
    590        attribute->attrib.ulValueLen = 0;
    591    }
    592    sftk_FreeAttribute(attribute);
    593 }
    594 
    595 static CK_RV
    596 sftk_forceTokenAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    597                         const void *value, unsigned int len)
    598 {
    599    CK_ATTRIBUTE attribute;
    600    SFTKDBHandle *dbHandle = NULL;
    601    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
    602    CK_RV crv;
    603 
    604    PORT_Assert(to);
    605    if (to == NULL) {
    606        return CKR_DEVICE_ERROR;
    607    }
    608 
    609    dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
    610 
    611    attribute.type = type;
    612    attribute.pValue = (void *)value;
    613    attribute.ulValueLen = len;
    614 
    615    crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1);
    616    sftk_freeDB(dbHandle);
    617    return crv;
    618 }
    619 
    620 /*
    621 * force an attribute to a specifc value.
    622 */
    623 CK_RV
    624 sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    625                    const void *value, unsigned int len)
    626 {
    627    SFTKAttribute *attribute;
    628    void *att_val = NULL;
    629    PRBool freeData = PR_FALSE;
    630 
    631    PORT_Assert(object);
    632    PORT_Assert(object->refCount);
    633    PORT_Assert(object->slot);
    634    if (!object ||
    635        !object->refCount ||
    636        !object->slot) {
    637        return CKR_DEVICE_ERROR;
    638    }
    639    /* validation flags are stored as FIPS indicators,
    640     * don't send them through the general attribute
    641     * parsing */
    642    if (type == CKA_OBJECT_VALIDATION_FLAGS) {
    643        CK_FLAGS validation;
    644        if (len != sizeof(CK_FLAGS)) {
    645            return CKR_ATTRIBUTE_VALUE_INVALID;
    646        }
    647        validation = *(CK_FLAGS *)value;
    648        /* we only understand FIPS currently, don't allow setting
    649         * other flags */
    650        if ((validation & ~SFTK_VALIDATION_FIPS_FLAG) != 0) {
    651            return CKR_ATTRIBUTE_VALUE_INVALID;
    652        }
    653        object->validation_value = validation;
    654        return CKR_OK;
    655    }
    656    if (sftk_isToken(object->handle)) {
    657        return sftk_forceTokenAttribute(object, type, value, len);
    658    }
    659    attribute = sftk_FindAttribute(object, type);
    660    if (attribute == NULL)
    661        return sftk_AddAttributeType(object, type, value, len);
    662 
    663    if (value) {
    664        if (len <= ATTR_SPACE) {
    665            att_val = attribute->space;
    666        } else {
    667            att_val = PORT_Alloc(len);
    668            freeData = PR_TRUE;
    669        }
    670        if (att_val == NULL) {
    671            return CKR_HOST_MEMORY;
    672        }
    673        if (attribute->attrib.pValue == att_val) {
    674            PORT_Memset(attribute->attrib.pValue, 0,
    675                        attribute->attrib.ulValueLen);
    676        }
    677        PORT_Memcpy(att_val, value, len);
    678    }
    679    if (attribute->attrib.pValue != NULL) {
    680        if (attribute->attrib.pValue != att_val) {
    681            PORT_Memset(attribute->attrib.pValue, 0,
    682                        attribute->attrib.ulValueLen);
    683        }
    684        if (attribute->freeData) {
    685            PORT_Free(attribute->attrib.pValue);
    686        }
    687        attribute->freeData = PR_FALSE;
    688        attribute->attrib.pValue = NULL;
    689        attribute->attrib.ulValueLen = 0;
    690    }
    691    if (att_val) {
    692        attribute->attrib.pValue = att_val;
    693        attribute->attrib.ulValueLen = len;
    694        attribute->freeData = freeData;
    695    }
    696    sftk_FreeAttribute(attribute);
    697    return CKR_OK;
    698 }
    699 
    700 /*
    701 * return a null terminated string from attribute 'type'. This string
    702 * is allocated and needs to be freed with PORT_Free() When complete.
    703 */
    704 char *
    705 sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
    706 {
    707    SFTKAttribute *attribute;
    708    char *label = NULL;
    709 
    710    attribute = sftk_FindAttribute(object, type);
    711    if (attribute == NULL)
    712        return NULL;
    713 
    714    if (attribute->attrib.pValue != NULL) {
    715        label = (char *)PORT_Alloc(attribute->attrib.ulValueLen + 1);
    716        if (label == NULL) {
    717            sftk_FreeAttribute(attribute);
    718            return NULL;
    719        }
    720 
    721        PORT_Memcpy(label, attribute->attrib.pValue,
    722                    attribute->attrib.ulValueLen);
    723        label[attribute->attrib.ulValueLen] = 0;
    724    }
    725    sftk_FreeAttribute(attribute);
    726    return label;
    727 }
    728 
    729 /*
    730 * decode when a particular attribute may be modified
    731 *  SFTK_NEVER: This attribute must be set at object creation time and
    732 *  can never be modified.
    733 *  SFTK_ONCOPY: This attribute may be modified only when you copy the
    734 *  object.
    735 *  SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
    736 *  CK_FALSE to CK_TRUE.
    737 *  SFTK_ALWAYS: This attribute can always be modified.
    738 * Some attributes vary their modification type based on the class of the
    739 *   object.
    740 */
    741 SFTKModifyType
    742 sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
    743 {
    744    /* if we don't know about it, user user defined, always allow modify */
    745    SFTKModifyType mtype = SFTK_ALWAYS;
    746 
    747    switch (type) {
    748        /* NEVER */
    749        case CKA_CLASS:
    750        case CKA_CERTIFICATE_TYPE:
    751        case CKA_KEY_TYPE:
    752        case CKA_MODULUS:
    753        case CKA_MODULUS_BITS:
    754        case CKA_PUBLIC_EXPONENT:
    755        case CKA_PRIVATE_EXPONENT:
    756        case CKA_PRIME:
    757        case CKA_BASE:
    758        case CKA_PRIME_1:
    759        case CKA_PRIME_2:
    760        case CKA_EXPONENT_1:
    761        case CKA_EXPONENT_2:
    762        case CKA_COEFFICIENT:
    763        case CKA_SEED:
    764        case CKA_PARAMETER_SET:
    765        case CKA_VALUE_LEN:
    766        case CKA_ALWAYS_SENSITIVE:
    767        case CKA_NEVER_EXTRACTABLE:
    768        case CKA_NSS_DB:
    769            mtype = SFTK_NEVER;
    770            break;
    771 
    772        /* ONCOPY */
    773        case CKA_TOKEN:
    774        case CKA_PRIVATE:
    775        case CKA_MODIFIABLE:
    776            mtype = SFTK_ONCOPY;
    777            break;
    778 
    779        /* SENSITIVE */
    780        case CKA_SENSITIVE:
    781        case CKA_EXTRACTABLE:
    782            mtype = SFTK_SENSITIVE;
    783            break;
    784 
    785        /* ALWAYS */
    786        case CKA_LABEL:
    787        case CKA_APPLICATION:
    788        case CKA_ID:
    789        case CKA_SERIAL_NUMBER:
    790        case CKA_START_DATE:
    791        case CKA_END_DATE:
    792        case CKA_DERIVE:
    793        case CKA_ENCRYPT:
    794        case CKA_DECRYPT:
    795        case CKA_SIGN:
    796        case CKA_VERIFY:
    797        case CKA_SIGN_RECOVER:
    798        case CKA_VERIFY_RECOVER:
    799        case CKA_WRAP:
    800        case CKA_UNWRAP:
    801            mtype = SFTK_ALWAYS;
    802            break;
    803 
    804        /* DEPENDS ON CLASS */
    805        case CKA_VALUE:
    806            mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
    807            break;
    808 
    809        case CKA_SUBPRIME:
    810            /* allow the CKA_SUBPRIME to be added to dh private keys */
    811            mtype = (inClass == CKO_PRIVATE_KEY) ? SFTK_ALWAYS : SFTK_NEVER;
    812            break;
    813 
    814        case CKA_SUBJECT:
    815            mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
    816            break;
    817        default:
    818            break;
    819    }
    820    return mtype;
    821 }
    822 
    823 /* decode if a particular attribute is sensitive (cannot be read
    824 * back to the user of if the object is set to SENSITIVE) */
    825 PRBool
    826 sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
    827 {
    828    switch (type) {
    829        /* ALWAYS */
    830        case CKA_PRIVATE_EXPONENT:
    831        case CKA_PRIME_1:
    832        case CKA_PRIME_2:
    833        case CKA_EXPONENT_1:
    834        case CKA_EXPONENT_2:
    835        case CKA_COEFFICIENT:
    836        case CKA_SEED:
    837            return PR_TRUE;
    838 
    839        /* DEPENDS ON CLASS */
    840        case CKA_VALUE:
    841            /* PRIVATE and SECRET KEYS have SENSITIVE values */
    842            return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
    843 
    844        default:
    845            break;
    846    }
    847    return PR_FALSE;
    848 }
    849 
    850 /*
    851 * copy an attribute into a SECItem. Secitem is allocated in the specified
    852 * arena.
    853 */
    854 CK_RV
    855 sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object,
    856                       CK_ATTRIBUTE_TYPE type)
    857 {
    858    int len;
    859    SFTKAttribute *attribute;
    860 
    861    attribute = sftk_FindAttribute(object, type);
    862    if (attribute == NULL)
    863        return CKR_TEMPLATE_INCOMPLETE;
    864    len = attribute->attrib.ulValueLen;
    865 
    866    if (arena) {
    867        item->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
    868    } else {
    869        item->data = (unsigned char *)PORT_Alloc(len);
    870    }
    871    if (item->data == NULL) {
    872        sftk_FreeAttribute(attribute);
    873        return CKR_HOST_MEMORY;
    874    }
    875    item->len = len;
    876    PORT_Memcpy(item->data, attribute->attrib.pValue, len);
    877    sftk_FreeAttribute(attribute);
    878    return CKR_OK;
    879 }
    880 
    881 CK_RV
    882 sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    883                       CK_ULONG *longData)
    884 {
    885    SFTKAttribute *attribute;
    886 
    887    attribute = sftk_FindAttribute(object, type);
    888    if (attribute == NULL)
    889        return CKR_TEMPLATE_INCOMPLETE;
    890 
    891    if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
    892        return CKR_ATTRIBUTE_VALUE_INVALID;
    893    }
    894 
    895    *longData = *(CK_ULONG *)attribute->attrib.pValue;
    896    sftk_FreeAttribute(attribute);
    897    return CKR_OK;
    898 }
    899 
    900 CK_RV
    901 sftk_ReadAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    902                   unsigned char *data, unsigned int maxLen, unsigned int *lenp)
    903 {
    904    SFTKAttribute *attribute;
    905 
    906    attribute = sftk_FindAttribute(object, type);
    907    if (attribute == NULL)
    908        return CKR_TEMPLATE_INCOMPLETE;
    909 
    910    *lenp = attribute->attrib.ulValueLen;
    911    if (*lenp > maxLen) {
    912        /* normally would be CKR_BUFFER_TOO_SMALL, but
    913         * it used with internal buffers, so if the value is
    914         * to long, the original attribute was invalid */
    915        return CKR_ATTRIBUTE_VALUE_INVALID;
    916    }
    917    PORT_Memcpy(data, attribute->attrib.pValue, *lenp);
    918    sftk_FreeAttribute(attribute);
    919    return CKR_OK;
    920 }
    921 
    922 void
    923 sftk_DeleteAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
    924 {
    925    SFTKAttribute *attribute;
    926    attribute = sftk_FindAttribute(object, type);
    927    if (attribute == NULL)
    928        return;
    929    sftk_DeleteAttribute(object, attribute);
    930    sftk_DestroyAttribute(attribute);
    931 }
    932 
    933 CK_RV
    934 sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    935                      const void *valPtr, CK_ULONG length)
    936 {
    937    SFTKAttribute *attribute;
    938    attribute = sftk_NewAttribute(object, type, valPtr, length);
    939    if (attribute == NULL) {
    940        return CKR_HOST_MEMORY;
    941    }
    942    sftk_AddAttribute(object, attribute);
    943    return CKR_OK;
    944 }
    945 
    946 /*
    947 * ******************** Object Utilities *******************************
    948 */
    949 
    950 /* must be called holding sftk_tokenKeyLock(slot) */
    951 static SECItem *
    952 sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
    953 {
    954    return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)(uintptr_t)handle);
    955 }
    956 
    957 /*
    958 * use the refLock. This operations should be very rare, so the added
    959 * contention on the ref lock should be lower than the overhead of adding
    960 * a new lock. We use separate functions for this just in case I'm wrong.
    961 */
    962 static void
    963 sftk_tokenKeyLock(SFTKSlot *slot)
    964 {
    965    SKIP_AFTER_FORK(PZ_Lock(slot->objectLock));
    966 }
    967 
    968 static void
    969 sftk_tokenKeyUnlock(SFTKSlot *slot)
    970 {
    971    SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock));
    972 }
    973 
    974 static PRIntn
    975 sftk_freeHashItem(PLHashEntry *entry, PRIntn index, void *arg)
    976 {
    977    SECItem *item = (SECItem *)entry->value;
    978 
    979    SECITEM_FreeItem(item, PR_TRUE);
    980    return HT_ENUMERATE_NEXT;
    981 }
    982 
    983 CK_RV
    984 SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
    985 {
    986    sftk_tokenKeyLock(slot);
    987    PORT_Assert(!slot->present);
    988    PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL);
    989    sftk_tokenKeyUnlock(slot);
    990    return CKR_OK;
    991 }
    992 
    993 /* allocation hooks that allow us to recycle old object structures */
    994 static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
    995 static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
    996 
    997 SFTKObject *
    998 sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace,
    999                       SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
   1000 {
   1001    SFTKObject *object;
   1002    int size = 0;
   1003 
   1004    if (!optimizeSpace) {
   1005        PZ_Lock(list->lock);
   1006        object = list->head;
   1007        if (object) {
   1008            list->head = object->next;
   1009            list->count--;
   1010        }
   1011        PZ_Unlock(list->lock);
   1012        if (object) {
   1013            // As a safeguard against misuse of the library, ensure we don't
   1014            // hand out live objects that somehow land in the free list.
   1015            PORT_Assert(object->refCount == 0);
   1016            if (object->refCount == 0) {
   1017                object->next = object->prev = NULL;
   1018                *hasLocks = PR_TRUE;
   1019                return object;
   1020            }
   1021        }
   1022    }
   1023    size = isSessionObject ? sizeof(SFTKSessionObject) + hashSize * sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
   1024 
   1025    object = (SFTKObject *)PORT_ZAlloc(size);
   1026    if (isSessionObject && object) {
   1027        ((SFTKSessionObject *)object)->hashSize = hashSize;
   1028    }
   1029    *hasLocks = PR_FALSE;
   1030    return object;
   1031 }
   1032 
   1033 static void
   1034 sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
   1035                     PRBool isSessionObject)
   1036 {
   1037 
   1038    /* the code below is equivalent to :
   1039     *     optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
   1040     * just faster.
   1041     */
   1042    PRBool optimizeSpace = isSessionObject &&
   1043                           ((SFTKSessionObject *)object)->optimizeSpace;
   1044    if (object->refLock && !optimizeSpace) {
   1045        PZ_Lock(list->lock);
   1046        if (list->count < MAX_OBJECT_LIST_SIZE) {
   1047            object->next = list->head;
   1048            list->head = object;
   1049            list->count++;
   1050            PZ_Unlock(list->lock);
   1051            return;
   1052        }
   1053        PZ_Unlock(list->lock);
   1054    }
   1055    if (isSessionObject) {
   1056        SFTKSessionObject *so = (SFTKSessionObject *)object;
   1057        PZ_DestroyLock(so->attributeLock);
   1058        so->attributeLock = NULL;
   1059    }
   1060    if (object->refLock) {
   1061        PZ_DestroyLock(object->refLock);
   1062        object->refLock = NULL;
   1063    }
   1064    PORT_Free(object);
   1065 }
   1066 
   1067 static SFTKObject *
   1068 sftk_freeObjectData(SFTKObject *object)
   1069 {
   1070    SFTKObject *next = object->next;
   1071 
   1072    PORT_Free(object);
   1073    return next;
   1074 }
   1075 
   1076 static void
   1077 sftk_InitFreeList(SFTKObjectFreeList *list)
   1078 {
   1079    if (!list->lock) {
   1080        list->lock = PZ_NewLock(nssILockObject);
   1081    }
   1082 }
   1083 
   1084 void
   1085 sftk_InitFreeLists(void)
   1086 {
   1087    sftk_InitFreeList(&sessionObjectList);
   1088    sftk_InitFreeList(&tokenObjectList);
   1089 }
   1090 
   1091 static void
   1092 sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
   1093 {
   1094    SFTKObject *object;
   1095 
   1096    if (!list->lock) {
   1097        return;
   1098    }
   1099    SKIP_AFTER_FORK(PZ_Lock(list->lock));
   1100    for (object = list->head; object != NULL;
   1101         object = sftk_freeObjectData(object)) {
   1102        PZ_DestroyLock(object->refLock);
   1103        if (isSessionList) {
   1104            PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
   1105        }
   1106    }
   1107    list->count = 0;
   1108    list->head = NULL;
   1109    SKIP_AFTER_FORK(PZ_Unlock(list->lock));
   1110    SKIP_AFTER_FORK(PZ_DestroyLock(list->lock));
   1111    list->lock = NULL;
   1112 }
   1113 
   1114 void
   1115 sftk_CleanupFreeLists(void)
   1116 {
   1117    sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
   1118    sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
   1119 }
   1120 
   1121 /*
   1122 * Create a new object
   1123 */
   1124 SFTKObject *
   1125 sftk_NewObject(SFTKSlot *slot)
   1126 {
   1127    SFTKObject *object;
   1128    SFTKSessionObject *sessObject;
   1129    PRBool hasLocks = PR_FALSE;
   1130    unsigned int i;
   1131    unsigned int hashSize = 0;
   1132 
   1133    hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE : TIME_ATTRIBUTE_HASH_SIZE;
   1134 
   1135    object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
   1136                                    &sessionObjectList, hashSize, PR_TRUE);
   1137    if (object == NULL) {
   1138        return NULL;
   1139    }
   1140    sessObject = (SFTKSessionObject *)object;
   1141    sessObject->nextAttr = 0;
   1142 
   1143    for (i = 0; i < MAX_OBJS_ATTRS; i++) {
   1144        sessObject->attrList[i].attrib.pValue = NULL;
   1145        sessObject->attrList[i].freeData = PR_FALSE;
   1146    }
   1147    sessObject->optimizeSpace = slot->optimizeSpace;
   1148 
   1149    object->handle = 0;
   1150    object->next = object->prev = NULL;
   1151    object->slot = slot;
   1152    /* set up the validation flags */
   1153    object->validation_value = 0;
   1154    object->validation_attribute.next = NULL;
   1155    object->validation_attribute.prev = NULL;
   1156    object->validation_attribute.freeAttr = PR_FALSE;
   1157    object->validation_attribute.freeData = PR_FALSE;
   1158    object->validation_attribute.handle = CKA_OBJECT_VALIDATION_FLAGS;
   1159    object->validation_attribute.attrib.type = CKA_OBJECT_VALIDATION_FLAGS;
   1160    object->validation_attribute.attrib.pValue = &object->validation_value;
   1161    object->validation_attribute.attrib.ulValueLen = sizeof(object->validation_value);
   1162    /* initialize the FIPS flag properly */
   1163    sftk_setFIPS(object, sftk_isFIPS(slot->slotID));
   1164 
   1165    object->refCount = 1;
   1166    sessObject->sessionList.next = NULL;
   1167    sessObject->sessionList.prev = NULL;
   1168    sessObject->sessionList.parent = object;
   1169    sessObject->session = NULL;
   1170    sessObject->wasDerived = PR_FALSE;
   1171    if (!hasLocks)
   1172        object->refLock = PZ_NewLock(nssILockRefLock);
   1173    if (object->refLock == NULL) {
   1174        PORT_Free(object);
   1175        return NULL;
   1176    }
   1177    if (!hasLocks)
   1178        sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
   1179    if (sessObject->attributeLock == NULL) {
   1180        PZ_DestroyLock(object->refLock);
   1181        PORT_Free(object);
   1182        return NULL;
   1183    }
   1184    for (i = 0; i < sessObject->hashSize; i++) {
   1185        sessObject->head[i] = NULL;
   1186    }
   1187    object->objectInfo = NULL;
   1188    object->infoFree = NULL;
   1189    return object;
   1190 }
   1191 
   1192 static CK_RV
   1193 sftk_DestroySessionObjectData(SFTKSessionObject *so)
   1194 {
   1195    int i;
   1196 
   1197    for (i = 0; i < MAX_OBJS_ATTRS; i++) {
   1198        unsigned char *value = so->attrList[i].attrib.pValue;
   1199        if (value) {
   1200            PORT_Memset(value, 0, so->attrList[i].attrib.ulValueLen);
   1201            if (so->attrList[i].freeData) {
   1202                PORT_Free(value);
   1203            }
   1204            so->attrList[i].attrib.pValue = NULL;
   1205            so->attrList[i].freeData = PR_FALSE;
   1206        }
   1207    }
   1208    /*  PZ_DestroyLock(so->attributeLock);*/
   1209    return CKR_OK;
   1210 }
   1211 
   1212 /*
   1213 * free all the data associated with an object. Object reference count must
   1214 * be 'zero'.
   1215 */
   1216 static CK_RV
   1217 sftk_DestroyObject(SFTKObject *object)
   1218 {
   1219    CK_RV crv = CKR_OK;
   1220    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
   1221    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
   1222 
   1223    PORT_Assert(object->refCount == 0);
   1224 
   1225    /* delete the database value */
   1226    if (to) {
   1227        if (to->dbKey.data) {
   1228            PORT_Free(to->dbKey.data);
   1229            to->dbKey.data = NULL;
   1230        }
   1231    }
   1232    if (so) {
   1233        sftk_DestroySessionObjectData(so);
   1234    }
   1235    if (object->objectInfo) {
   1236        (*object->infoFree)(object->objectInfo);
   1237        object->objectInfo = NULL;
   1238        object->infoFree = NULL;
   1239    }
   1240    if (so) {
   1241        sftk_PutObjectToList(object, &sessionObjectList, PR_TRUE);
   1242    } else {
   1243        sftk_PutObjectToList(object, &tokenObjectList, PR_FALSE);
   1244    }
   1245    return crv;
   1246 }
   1247 
   1248 void
   1249 sftk_ReferenceObject(SFTKObject *object)
   1250 {
   1251    PZ_Lock(object->refLock);
   1252    PORT_Assert(object->refCount > 0);
   1253    object->refCount++;
   1254    PZ_Unlock(object->refLock);
   1255 }
   1256 
   1257 static SFTKObject *
   1258 sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
   1259 {
   1260    SFTKObject *object;
   1261    PRUint32 index = sftk_hash(handle, slot->sessObjHashSize);
   1262 
   1263    if (sftk_isToken(handle)) {
   1264        return sftk_NewTokenObject(slot, NULL, handle);
   1265    }
   1266 
   1267    PZ_Lock(slot->objectLock);
   1268    sftkqueue_find2(object, handle, index, slot->sessObjHashTable);
   1269    if (object) {
   1270        sftk_ReferenceObject(object);
   1271    }
   1272    PZ_Unlock(slot->objectLock);
   1273 
   1274    return (object);
   1275 }
   1276 /*
   1277 * look up and object structure from a handle. OBJECT_Handles only make
   1278 * sense in terms of a given session.  make a reference to that object
   1279 * structure returned.
   1280 */
   1281 SFTKObject *
   1282 sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
   1283 {
   1284    SFTKSlot *slot = sftk_SlotFromSession(session);
   1285 
   1286    return sftk_ObjectFromHandleOnSlot(handle, slot);
   1287 }
   1288 
   1289 /*
   1290 * release a reference to an object handle
   1291 */
   1292 SFTKFreeStatus
   1293 sftk_FreeObject(SFTKObject *object)
   1294 {
   1295    PRBool destroy = PR_FALSE;
   1296    CK_RV crv;
   1297 
   1298    PZ_Lock(object->refLock);
   1299    if (object->refCount == 1)
   1300        destroy = PR_TRUE;
   1301    object->refCount--;
   1302    PZ_Unlock(object->refLock);
   1303 
   1304    if (destroy) {
   1305        crv = sftk_DestroyObject(object);
   1306        if (crv != CKR_OK) {
   1307            return SFTK_DestroyFailure;
   1308        }
   1309        return SFTK_Destroyed;
   1310    }
   1311    return SFTK_Busy;
   1312 }
   1313 
   1314 /* find the next available object handle that isn't currently in use */
   1315 /* NOTE: This function could loop forever if we've exhausted all
   1316 * 3^31-1 handles. This is highly unlikely (NSS has been running for
   1317 * decades with this code) uless we start increasing the size of the
   1318 * SFTK_TOKEN_MASK (which is just the high bit currently). */
   1319 CK_OBJECT_HANDLE
   1320 sftk_getNextHandle(SFTKSlot *slot)
   1321 {
   1322    CK_OBJECT_HANDLE handle;
   1323    SFTKObject *duplicateObject = NULL;
   1324    do {
   1325        PRUint32 wrappedAround;
   1326 
   1327        duplicateObject = NULL;
   1328        PZ_Lock(slot->objectLock);
   1329        wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;
   1330        handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
   1331        if (!handle) /* don't allow zero handle */
   1332            handle = NSC_MIN_SESSION_OBJECT_HANDLE;
   1333        slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
   1334        /* Is there already a session object with this handle? */
   1335        if (wrappedAround) {
   1336            sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,
   1337                           slot->sessObjHashSize);
   1338        }
   1339        PZ_Unlock(slot->objectLock);
   1340    } while (duplicateObject != NULL);
   1341    return handle;
   1342 }
   1343 
   1344 /*
   1345 * add an object to a slot and session queue. These two functions
   1346 * adopt the object.
   1347 */
   1348 void
   1349 sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
   1350 {
   1351    PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
   1352    sftkqueue_init_element(object);
   1353    PZ_Lock(slot->objectLock);
   1354    sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable);
   1355    PZ_Unlock(slot->objectLock);
   1356 }
   1357 
   1358 void
   1359 sftk_AddObject(SFTKSession *session, SFTKObject *object)
   1360 {
   1361    SFTKSlot *slot = sftk_SlotFromSession(session);
   1362    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
   1363 
   1364    if (so) {
   1365        PZ_Lock(session->objectLock);
   1366        sftkqueue_add(&so->sessionList, 0, session->objects, 0);
   1367        so->session = session;
   1368        PZ_Unlock(session->objectLock);
   1369    }
   1370    sftk_AddSlotObject(slot, object);
   1371    sftk_ReferenceObject(object);
   1372 }
   1373 
   1374 /*
   1375 * delete an object from a slot and session queue
   1376 */
   1377 CK_RV
   1378 sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
   1379 {
   1380    SFTKSlot *slot = sftk_SlotFromSession(session);
   1381    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
   1382    CK_RV crv = CKR_OK;
   1383    PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
   1384 
   1385    /* Handle Token case */
   1386    if (so && so->session) {
   1387        session = so->session;
   1388        PZ_Lock(session->objectLock);
   1389        sftkqueue_delete(&so->sessionList, 0, session->objects, 0);
   1390        PZ_Unlock(session->objectLock);
   1391        PZ_Lock(slot->objectLock);
   1392        sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable);
   1393        PZ_Unlock(slot->objectLock);
   1394        sftkqueue_clear_deleted_element(object);
   1395        sftk_FreeObject(object); /* free the reference owned by the queue */
   1396    } else {
   1397        SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle);
   1398 #ifdef DEBUG
   1399        SFTKTokenObject *to = sftk_narrowToTokenObject(object);
   1400        PORT_Assert(to);
   1401 #endif
   1402        crv = sftkdb_DestroyObject(handle, object->handle, object->objclass);
   1403        sftk_freeDB(handle);
   1404    }
   1405    return crv;
   1406 }
   1407 
   1408 /*
   1409 * Token objects don't explicitly store their attributes, so we need to know
   1410 * what attributes make up a particular token object before we can copy it.
   1411 * below are the tables by object type.
   1412 */
   1413 static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
   1414    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
   1415 };
   1416 static const CK_ULONG commonAttrsCount =
   1417    sizeof(commonAttrs) / sizeof(commonAttrs[0]);
   1418 
   1419 static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
   1420    CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
   1421 };
   1422 static const CK_ULONG commonKeyAttrsCount =
   1423    sizeof(commonKeyAttrs) / sizeof(commonKeyAttrs[0]);
   1424 
   1425 static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
   1426    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
   1427    CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
   1428 };
   1429 static const CK_ULONG secretKeyAttrsCount =
   1430    sizeof(secretKeyAttrs) / sizeof(secretKeyAttrs[0]);
   1431 
   1432 static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
   1433    CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
   1434 };
   1435 static const CK_ULONG commonPubKeyAttrsCount =
   1436    sizeof(commonPubKeyAttrs) / sizeof(commonPubKeyAttrs[0]);
   1437 
   1438 static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
   1439    CKA_MODULUS, CKA_PUBLIC_EXPONENT
   1440 };
   1441 static const CK_ULONG rsaPubKeyAttrsCount =
   1442    sizeof(rsaPubKeyAttrs) / sizeof(rsaPubKeyAttrs[0]);
   1443 
   1444 static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
   1445    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
   1446 };
   1447 static const CK_ULONG dsaPubKeyAttrsCount =
   1448    sizeof(dsaPubKeyAttrs) / sizeof(dsaPubKeyAttrs[0]);
   1449 
   1450 static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
   1451    CKA_PRIME, CKA_BASE, CKA_VALUE
   1452 };
   1453 static const CK_ULONG dhPubKeyAttrsCount =
   1454    sizeof(dhPubKeyAttrs) / sizeof(dhPubKeyAttrs[0]);
   1455 static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
   1456    CKA_EC_PARAMS, CKA_EC_POINT
   1457 };
   1458 static const CK_ULONG ecPubKeyAttrsCount =
   1459    sizeof(ecPubKeyAttrs) / sizeof(ecPubKeyAttrs[0]);
   1460 
   1461 static const CK_ATTRIBUTE_TYPE mldsaPubKeyAttrs[] = {
   1462    CKA_PARAMETER_SET, CKA_VALUE
   1463 };
   1464 static const CK_ULONG mldsaPubKeyAttrsCount = PR_ARRAY_SIZE(mldsaPubKeyAttrs);
   1465 
   1466 static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
   1467    CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
   1468    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NSS_DB, CKA_PUBLIC_KEY_INFO
   1469 };
   1470 static const CK_ULONG commonPrivKeyAttrsCount =
   1471    sizeof(commonPrivKeyAttrs) / sizeof(commonPrivKeyAttrs[0]);
   1472 
   1473 static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
   1474    CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
   1475    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
   1476 };
   1477 static const CK_ULONG rsaPrivKeyAttrsCount =
   1478    sizeof(rsaPrivKeyAttrs) / sizeof(rsaPrivKeyAttrs[0]);
   1479 
   1480 static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
   1481    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
   1482 };
   1483 static const CK_ULONG dsaPrivKeyAttrsCount =
   1484    sizeof(dsaPrivKeyAttrs) / sizeof(dsaPrivKeyAttrs[0]);
   1485 
   1486 static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
   1487    CKA_PRIME, CKA_BASE, CKA_VALUE
   1488 };
   1489 static const CK_ULONG dhPrivKeyAttrsCount =
   1490    sizeof(dhPrivKeyAttrs) / sizeof(dhPrivKeyAttrs[0]);
   1491 static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
   1492    CKA_EC_PARAMS, CKA_VALUE
   1493 };
   1494 static const CK_ULONG ecPrivKeyAttrsCount =
   1495    sizeof(ecPrivKeyAttrs) / sizeof(ecPrivKeyAttrs[0]);
   1496 
   1497 static const CK_ATTRIBUTE_TYPE mldsaPrivKeyAttrs[] = {
   1498    CKA_PARAMETER_SET, CKA_VALUE, CKA_SEED
   1499 };
   1500 static const CK_ULONG mldsaPrivKeyAttrsCount = PR_ARRAY_SIZE(mldsaPrivKeyAttrs);
   1501 
   1502 static const CK_ATTRIBUTE_TYPE certAttrs[] = {
   1503    CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
   1504 };
   1505 static const CK_ULONG certAttrsCount =
   1506    sizeof(certAttrs) / sizeof(certAttrs[0]);
   1507 
   1508 static const CK_ATTRIBUTE_TYPE nssTrustAttrs[] = {
   1509    CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_NSS_CERT_SHA1_HASH,
   1510    CKA_NSS_CERT_MD5_HASH, CKA_NSS_TRUST_SERVER_AUTH, CKA_NSS_TRUST_CLIENT_AUTH,
   1511    CKA_NSS_TRUST_EMAIL_PROTECTION, CKA_NSS_TRUST_CODE_SIGNING,
   1512    CKA_NSS_TRUST_STEP_UP_APPROVED
   1513 };
   1514 static const CK_ULONG nssTrustAttrsCount =
   1515    sizeof(nssTrustAttrs) / sizeof(nssTrustAttrs[0]);
   1516 
   1517 static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
   1518    CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_HASH_OF_CERTIFICATE,
   1519    CKA_NAME_HASH_ALGORITHM, CKA_PKCS_TRUST_SERVER_AUTH,
   1520    CKA_PKCS_TRUST_CLIENT_AUTH, CKA_PKCS_TRUST_EMAIL_PROTECTION,
   1521    CKA_PKCS_TRUST_CODE_SIGNING
   1522 };
   1523 static const CK_ULONG trustAttrsCount =
   1524    sizeof(trustAttrs) / sizeof(trustAttrs[0]);
   1525 
   1526 static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
   1527    CKA_SUBJECT, CKA_NSS_EMAIL, CKA_NSS_SMIME_TIMESTAMP, CKA_VALUE
   1528 };
   1529 static const CK_ULONG smimeAttrsCount =
   1530    sizeof(smimeAttrs) / sizeof(smimeAttrs[0]);
   1531 
   1532 static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
   1533    CKA_SUBJECT, CKA_VALUE, CKA_NSS_URL, CKA_NSS_KRL
   1534 };
   1535 static const CK_ULONG crlAttrsCount =
   1536    sizeof(crlAttrs) / sizeof(crlAttrs[0]);
   1537 
   1538 /* copy an object based on it's table */
   1539 CK_RV
   1540 stfk_CopyTokenAttributes(SFTKObject *destObject, SFTKTokenObject *src_to,
   1541                         const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
   1542 {
   1543    SFTKAttribute *attribute;
   1544    SFTKAttribute *newAttribute;
   1545    CK_RV crv = CKR_OK;
   1546    unsigned int i;
   1547 
   1548    for (i = 0; i < attrCount; i++) {
   1549        if (!sftk_hasAttribute(destObject, attrArray[i])) {
   1550            attribute = sftk_FindAttribute(&src_to->obj, attrArray[i]);
   1551            if (!attribute) {
   1552                continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
   1553            }
   1554            /* we need to copy the attribute since each attribute
   1555             * only has one set of link list pointers */
   1556            newAttribute = sftk_NewAttribute(destObject,
   1557                                             sftk_attr_expand(&attribute->attrib));
   1558            sftk_FreeAttribute(attribute); /* free the old attribute */
   1559            if (!newAttribute) {
   1560                return CKR_HOST_MEMORY;
   1561            }
   1562            sftk_AddAttribute(destObject, newAttribute);
   1563        }
   1564    }
   1565    return crv;
   1566 }
   1567 
   1568 CK_RV
   1569 stfk_CopyTokenPrivateKey(SFTKObject *destObject, SFTKTokenObject *src_to)
   1570 {
   1571    CK_RV crv;
   1572    CK_KEY_TYPE key_type;
   1573    SFTKAttribute *attribute;
   1574 
   1575    /* copy the common attributes for all keys first */
   1576    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
   1577                                   commonKeyAttrsCount);
   1578    if (crv != CKR_OK) {
   1579        goto fail;
   1580    }
   1581    /* copy the common attributes for all private keys next */
   1582    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
   1583                                   commonPrivKeyAttrsCount);
   1584    if (crv != CKR_OK) {
   1585        goto fail;
   1586    }
   1587    attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
   1588    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
   1589                             * copying the common attributes */
   1590    if (!attribute) {
   1591        /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
   1592         * the fact is, the only reason we couldn't get the attribute would
   1593         * be a memory error or database error (an error in the 'device').
   1594         * if we have a database error code, we could return it here */
   1595        crv = CKR_DEVICE_ERROR;
   1596        goto fail;
   1597    }
   1598    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
   1599    sftk_FreeAttribute(attribute);
   1600 
   1601    /* finally copy the attributes for various private key types */
   1602    switch (key_type) {
   1603        case CKK_RSA:
   1604            crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
   1605                                           rsaPrivKeyAttrsCount);
   1606            break;
   1607        case CKK_DSA:
   1608            crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
   1609                                           dsaPrivKeyAttrsCount);
   1610            break;
   1611        case CKK_ML_DSA:
   1612            crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPrivKeyAttrs,
   1613                                           mldsaPrivKeyAttrsCount);
   1614            break;
   1615        case CKK_DH:
   1616            crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
   1617                                           dhPrivKeyAttrsCount);
   1618            break;
   1619        case CKK_EC:
   1620            crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
   1621                                           ecPrivKeyAttrsCount);
   1622            break;
   1623        default:
   1624            crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
   1625                                     * of token keys into our database. */
   1626    }
   1627 fail:
   1628    return crv;
   1629 }
   1630 
   1631 CK_RV
   1632 stfk_CopyTokenPublicKey(SFTKObject *destObject, SFTKTokenObject *src_to)
   1633 {
   1634    CK_RV crv;
   1635    CK_KEY_TYPE key_type;
   1636    SFTKAttribute *attribute;
   1637 
   1638    /* copy the common attributes for all keys first */
   1639    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
   1640                                   commonKeyAttrsCount);
   1641    if (crv != CKR_OK) {
   1642        goto fail;
   1643    }
   1644 
   1645    /* copy the common attributes for all public keys next */
   1646    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
   1647                                   commonPubKeyAttrsCount);
   1648    if (crv != CKR_OK) {
   1649        goto fail;
   1650    }
   1651    attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
   1652    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
   1653                             * copying the common attributes */
   1654    if (!attribute) {
   1655        /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
   1656         * the fact is, the only reason we couldn't get the attribute would
   1657         * be a memory error or database error (an error in the 'device').
   1658         * if we have a database error code, we could return it here */
   1659        crv = CKR_DEVICE_ERROR;
   1660        goto fail;
   1661    }
   1662    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
   1663    sftk_FreeAttribute(attribute);
   1664 
   1665    /* finally copy the attributes for various public key types */
   1666    switch (key_type) {
   1667        case CKK_RSA:
   1668            crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
   1669                                           rsaPubKeyAttrsCount);
   1670            break;
   1671        case CKK_DSA:
   1672            crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
   1673                                           dsaPubKeyAttrsCount);
   1674            break;
   1675        case CKK_ML_DSA:
   1676            crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPubKeyAttrs,
   1677                                           mldsaPubKeyAttrsCount);
   1678            break;
   1679        case CKK_DH:
   1680            crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
   1681                                           dhPubKeyAttrsCount);
   1682            break;
   1683        case CKK_EC:
   1684            crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
   1685                                           ecPubKeyAttrsCount);
   1686            break;
   1687        default:
   1688            crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
   1689                                     * of token keys into our database. */
   1690    }
   1691 fail:
   1692    return crv;
   1693 }
   1694 CK_RV
   1695 stfk_CopyTokenSecretKey(SFTKObject *destObject, SFTKTokenObject *src_to)
   1696 {
   1697    CK_RV crv;
   1698    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
   1699                                   commonKeyAttrsCount);
   1700    if (crv != CKR_OK) {
   1701        goto fail;
   1702    }
   1703    crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
   1704                                   secretKeyAttrsCount);
   1705 fail:
   1706    return crv;
   1707 }
   1708 
   1709 /*
   1710 * Copy a token object. We need to explicitly copy the relevant
   1711 * attributes since token objects don't store those attributes in
   1712 * the token itself.
   1713 */
   1714 CK_RV
   1715 sftk_CopyTokenObject(SFTKObject *destObject, SFTKObject *srcObject)
   1716 {
   1717    SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
   1718    CK_RV crv;
   1719 
   1720    PORT_Assert(src_to);
   1721    if (src_to == NULL) {
   1722        return CKR_DEVICE_ERROR; /* internal state inconsistant */
   1723    }
   1724 
   1725    crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
   1726                                   commonAttrsCount);
   1727    if (crv != CKR_OK) {
   1728        goto fail;
   1729    }
   1730    switch (src_to->obj.objclass) {
   1731        case CKO_CERTIFICATE:
   1732            crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
   1733                                           certAttrsCount);
   1734            break;
   1735        case CKO_NSS_TRUST:
   1736            crv = stfk_CopyTokenAttributes(destObject, src_to, nssTrustAttrs,
   1737                                           nssTrustAttrsCount);
   1738            break;
   1739        case CKO_TRUST:
   1740            crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
   1741                                           trustAttrsCount);
   1742            break;
   1743        case CKO_NSS_SMIME:
   1744            crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
   1745                                           smimeAttrsCount);
   1746            break;
   1747        case CKO_NSS_CRL:
   1748            crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
   1749                                           crlAttrsCount);
   1750            break;
   1751        case CKO_PRIVATE_KEY:
   1752            crv = stfk_CopyTokenPrivateKey(destObject, src_to);
   1753            break;
   1754        case CKO_PUBLIC_KEY:
   1755            crv = stfk_CopyTokenPublicKey(destObject, src_to);
   1756            break;
   1757        case CKO_SECRET_KEY:
   1758            crv = stfk_CopyTokenSecretKey(destObject, src_to);
   1759            break;
   1760        default:
   1761            crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
   1762                                     * of token keys into our database. */
   1763    }
   1764 fail:
   1765    return crv;
   1766 }
   1767 
   1768 /*
   1769 * copy the attributes from one object to another. Don't overwrite existing
   1770 * attributes. NOTE: This is a pretty expensive operation since it
   1771 * grabs the attribute locks for the src object for a *long* time.
   1772 */
   1773 CK_RV
   1774 sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
   1775 {
   1776    SFTKAttribute *attribute;
   1777    SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
   1778    unsigned int i;
   1779 
   1780    destObject->validation_value = srcObject->validation_value;
   1781    if (src_so == NULL) {
   1782        return sftk_CopyTokenObject(destObject, srcObject);
   1783    }
   1784 
   1785    PZ_Lock(src_so->attributeLock);
   1786    for (i = 0; i < src_so->hashSize; i++) {
   1787        attribute = src_so->head[i];
   1788        do {
   1789            if (attribute) {
   1790                if (!sftk_hasAttribute(destObject, attribute->handle)) {
   1791                    /* we need to copy the attribute since each attribute
   1792                     * only has one set of link list pointers */
   1793                    SFTKAttribute *newAttribute = sftk_NewAttribute(
   1794                        destObject, sftk_attr_expand(&attribute->attrib));
   1795                    if (newAttribute == NULL) {
   1796                        PZ_Unlock(src_so->attributeLock);
   1797                        return CKR_HOST_MEMORY;
   1798                    }
   1799                    sftk_AddAttribute(destObject, newAttribute);
   1800                }
   1801                attribute = attribute->next;
   1802            }
   1803        } while (attribute != NULL);
   1804    }
   1805    PZ_Unlock(src_so->attributeLock);
   1806 
   1807    return CKR_OK;
   1808 }
   1809 
   1810 /*
   1811 * ******************** Search Utilities *******************************
   1812 */
   1813 
   1814 /* add an object to a search list */
   1815 CK_RV
   1816 AddToList(SFTKObjectListElement **list, SFTKObject *object)
   1817 {
   1818    SFTKObjectListElement *newElem =
   1819        (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
   1820 
   1821    if (newElem == NULL)
   1822        return CKR_HOST_MEMORY;
   1823 
   1824    newElem->next = *list;
   1825    newElem->object = object;
   1826    sftk_ReferenceObject(object);
   1827 
   1828    *list = newElem;
   1829    return CKR_OK;
   1830 }
   1831 
   1832 /* return true if the object matches the template */
   1833 PRBool
   1834 sftk_objectMatch(SFTKObject *object, CK_ATTRIBUTE_PTR theTemplate, int count)
   1835 {
   1836    int i;
   1837 
   1838    for (i = 0; i < count; i++) {
   1839        SFTKAttribute *attribute = sftk_FindAttribute(object, theTemplate[i].type);
   1840        if (attribute == NULL) {
   1841            return PR_FALSE;
   1842        }
   1843        if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
   1844            if (PORT_Memcmp(attribute->attrib.pValue, theTemplate[i].pValue,
   1845                            theTemplate[i].ulValueLen) == 0) {
   1846                sftk_FreeAttribute(attribute);
   1847                continue;
   1848            }
   1849        }
   1850        sftk_FreeAttribute(attribute);
   1851        return PR_FALSE;
   1852    }
   1853    return PR_TRUE;
   1854 }
   1855 
   1856 /* search through all the objects in the queue and return the template matches
   1857 * in the object list.
   1858 */
   1859 CK_RV
   1860 sftk_searchObjectList(SFTKSearchResults *search, SFTKObject **head,
   1861                      unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate,
   1862                      int count, PRBool isLoggedIn)
   1863 {
   1864    unsigned int i;
   1865    SFTKObject *object;
   1866    CK_RV crv = CKR_OK;
   1867 
   1868    PZ_Lock(lock);
   1869    for (i = 0; i < size; i++) {
   1870        for (object = head[i]; object != NULL; object = object->next) {
   1871            if (sftk_objectMatch(object, theTemplate, count)) {
   1872                /* don't return objects that aren't yet visible */
   1873                if ((!isLoggedIn) && sftk_isTrue(object, CKA_PRIVATE))
   1874                    continue;
   1875                sftk_addHandle(search, object->handle);
   1876            }
   1877        }
   1878    }
   1879    PZ_Unlock(lock);
   1880    return crv;
   1881 }
   1882 
   1883 /*
   1884 * free a single list element. Return the Next object in the list.
   1885 */
   1886 SFTKObjectListElement *
   1887 sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
   1888 {
   1889    SFTKObjectListElement *ol = objectList->next;
   1890 
   1891    sftk_FreeObject(objectList->object);
   1892    PORT_Free(objectList);
   1893    return ol;
   1894 }
   1895 
   1896 /* free an entire object list */
   1897 void
   1898 sftk_FreeObjectList(SFTKObjectListElement *objectList)
   1899 {
   1900    SFTKObjectListElement *ol;
   1901 
   1902    for (ol = objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {
   1903    }
   1904 }
   1905 
   1906 /*
   1907 * free a search structure
   1908 */
   1909 void
   1910 sftk_FreeSearch(SFTKSearchResults *search)
   1911 {
   1912    if (search->handles) {
   1913        PORT_Free(search->handles);
   1914    }
   1915    PORT_Free(search);
   1916 }
   1917 
   1918 /*
   1919 * ******************** Session Utilities *******************************
   1920 */
   1921 
   1922 /* update the sessions state based in it's flags and wether or not it's
   1923 * logged in */
   1924 void
   1925 sftk_update_state(SFTKSlot *slot, SFTKSession *session)
   1926 {
   1927    if (slot->isLoggedIn) {
   1928        if (slot->ssoLoggedIn) {
   1929            session->info.state = CKS_RW_SO_FUNCTIONS;
   1930        } else if (session->info.flags & CKF_RW_SESSION) {
   1931            session->info.state = CKS_RW_USER_FUNCTIONS;
   1932        } else {
   1933            session->info.state = CKS_RO_USER_FUNCTIONS;
   1934        }
   1935    } else {
   1936        if (session->info.flags & CKF_RW_SESSION) {
   1937            session->info.state = CKS_RW_PUBLIC_SESSION;
   1938        } else {
   1939            session->info.state = CKS_RO_PUBLIC_SESSION;
   1940        }
   1941    }
   1942 }
   1943 
   1944 /* update the state of all the sessions on a slot */
   1945 void
   1946 sftk_update_all_states(SFTKSlot *slot)
   1947 {
   1948    unsigned int i;
   1949    SFTKSession *session;
   1950 
   1951    for (i = 0; i < slot->sessHashSize; i++) {
   1952        PZLock *lock = SFTK_SESSION_LOCK(slot, i);
   1953        PZ_Lock(lock);
   1954        for (session = slot->head[i]; session; session = session->next) {
   1955            sftk_update_state(slot, session);
   1956        }
   1957        PZ_Unlock(lock);
   1958    }
   1959 }
   1960 
   1961 /*
   1962 * context are cipher and digest contexts that are associated with a session
   1963 */
   1964 void
   1965 sftk_FreeContext(SFTKSessionContext *context)
   1966 {
   1967    if (context->cipherInfo) {
   1968        (*context->destroy)(context->cipherInfo, PR_TRUE);
   1969    }
   1970    if (context->hashInfo) {
   1971        (*context->hashdestroy)(context->hashInfo, PR_TRUE);
   1972    }
   1973    if (context->key) {
   1974        sftk_FreeObject(context->key);
   1975        context->key = NULL;
   1976    }
   1977    if (context->signature) {
   1978        SECITEM_FreeItem(context->signature, PR_TRUE);
   1979        context->signature = NULL;
   1980    }
   1981    PORT_Free(context);
   1982 }
   1983 
   1984 /*
   1985 * Init a new session. NOTE: The session handle is not set, and the
   1986 * session is not added to the slot's session queue.
   1987 */
   1988 CK_RV
   1989 sftk_InitSession(SFTKSession *session, SFTKSlot *slot, CK_SLOT_ID slotID,
   1990                 CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags)
   1991 {
   1992    session->next = session->prev = NULL;
   1993    session->enc_context = NULL;
   1994    session->hash_context = NULL;
   1995    session->sign_context = NULL;
   1996    session->search = NULL;
   1997    session->objectIDCount = 1;
   1998    session->objectLock = PZ_NewLock(nssILockObject);
   1999    if (session->objectLock == NULL) {
   2000        return CKR_HOST_MEMORY;
   2001    }
   2002    session->objects[0] = NULL;
   2003 
   2004    session->slot = slot;
   2005    session->notify = notify;
   2006    session->appData = pApplication;
   2007    session->info.flags = flags;
   2008    session->info.slotID = slotID;
   2009    session->info.ulDeviceError = 0;
   2010    sftk_update_state(slot, session);
   2011    /* no ops completed yet, so the last one couldn't be a FIPS op */
   2012    session->lastOpWasFIPS = PR_FALSE;
   2013    return CKR_OK;
   2014 }
   2015 
   2016 /*
   2017 * Create a new session and init it.
   2018 */
   2019 SFTKSession *
   2020 sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
   2021                CK_FLAGS flags)
   2022 {
   2023    SFTKSession *session;
   2024    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
   2025    CK_RV crv;
   2026 
   2027    if (slot == NULL)
   2028        return NULL;
   2029 
   2030    session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));
   2031    if (session == NULL)
   2032        return NULL;
   2033 
   2034    crv = sftk_InitSession(session, slot, slotID, notify, pApplication, flags);
   2035    if (crv != CKR_OK) {
   2036        PORT_Free(session);
   2037        return NULL;
   2038    }
   2039    return session;
   2040 }
   2041 
   2042 /* free all the data associated with a session. */
   2043 void
   2044 sftk_ClearSession(SFTKSession *session)
   2045 {
   2046    SFTKObjectList *op, *next;
   2047 
   2048    /* clean out the attributes */
   2049    /* since no one is referencing us, it's safe to walk the chain
   2050     * without a lock */
   2051    for (op = session->objects[0]; op != NULL; op = next) {
   2052        next = op->next;
   2053        /* paranoia */
   2054        op->next = op->prev = NULL;
   2055        sftk_DeleteObject(session, op->parent);
   2056    }
   2057    PZ_DestroyLock(session->objectLock);
   2058    if (session->enc_context) {
   2059        sftk_FreeContext(session->enc_context);
   2060    }
   2061    if (session->hash_context) {
   2062        sftk_FreeContext(session->hash_context);
   2063    }
   2064    if (session->sign_context) {
   2065        sftk_FreeContext(session->sign_context);
   2066    }
   2067    if (session->search) {
   2068        sftk_FreeSearch(session->search);
   2069    }
   2070 }
   2071 
   2072 /* free the data associated with the session, and the session */
   2073 void
   2074 sftk_DestroySession(SFTKSession *session)
   2075 {
   2076    sftk_ClearSession(session);
   2077    PORT_Free(session);
   2078 }
   2079 
   2080 /*
   2081 * look up a session structure from a session handle
   2082 * generate a reference to it.
   2083 */
   2084 SFTKSession *
   2085 sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
   2086 {
   2087    SFTKSlot *slot = sftk_SlotFromSessionHandle(handle);
   2088    SFTKSession *session;
   2089    PZLock *lock;
   2090 
   2091    if (!slot)
   2092        return NULL;
   2093    lock = SFTK_SESSION_LOCK(slot, handle);
   2094 
   2095    PZ_Lock(lock);
   2096    sftkqueue_find(session, handle, slot->head, slot->sessHashSize);
   2097    PZ_Unlock(lock);
   2098 
   2099    return (session);
   2100 }
   2101 
   2102 /*
   2103 * release a reference to a session handle. This method of using SFTKSessions
   2104 * is deprecated, but the pattern should be retained until a future effort
   2105 * to refactor all SFTKSession users at once is completed.
   2106 */
   2107 void
   2108 sftk_FreeSession(SFTKSession *session)
   2109 {
   2110    return;
   2111 }
   2112 
   2113 void
   2114 sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
   2115 {
   2116    if (search->handles == NULL) {
   2117        return;
   2118    }
   2119    if (search->size >= search->array_size) {
   2120        search->array_size += NSC_SEARCH_BLOCK_SIZE;
   2121        search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
   2122                                                           sizeof(CK_OBJECT_HANDLE) * search->array_size);
   2123        if (search->handles == NULL) {
   2124            return;
   2125        }
   2126    }
   2127    search->handles[search->size] = handle;
   2128    search->size++;
   2129 }
   2130 
   2131 static CK_RV
   2132 handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle,
   2133              CK_OBJECT_CLASS *objClass)
   2134 {
   2135    SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle);
   2136    CK_ATTRIBUTE objClassTemplate;
   2137    CK_RV crv;
   2138 
   2139    *objClass = CKO_DATA;
   2140    objClassTemplate.type = CKA_CLASS;
   2141    objClassTemplate.pValue = objClass;
   2142    objClassTemplate.ulValueLen = sizeof(*objClass);
   2143    crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1);
   2144    sftk_freeDB(dbHandle);
   2145    return crv;
   2146 }
   2147 
   2148 SFTKObject *
   2149 sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
   2150 {
   2151    SFTKObject *object = NULL;
   2152    PRBool hasLocks = PR_FALSE;
   2153    CK_RV crv;
   2154 
   2155    object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0,
   2156                                    PR_FALSE);
   2157    if (object == NULL) {
   2158        return NULL;
   2159    }
   2160 
   2161    object->handle = handle;
   2162    /* every object must have a class, if we can't get it, the object
   2163     * doesn't exist */
   2164    crv = handleToClass(slot, handle, &object->objclass);
   2165    if (crv != CKR_OK) {
   2166        goto loser;
   2167    }
   2168    object->slot = slot;
   2169    /* set up the validation flags */
   2170    object->validation_value = 0;
   2171    object->validation_attribute.next = NULL;
   2172    object->validation_attribute.prev = NULL;
   2173    object->validation_attribute.freeAttr = PR_FALSE;
   2174    object->validation_attribute.freeData = PR_FALSE;
   2175    object->validation_attribute.handle = CKA_OBJECT_VALIDATION_FLAGS;
   2176    object->validation_attribute.attrib.type = CKA_OBJECT_VALIDATION_FLAGS;
   2177    object->validation_attribute.attrib.pValue = &object->validation_value;
   2178    object->validation_attribute.attrib.ulValueLen = sizeof(object->validation_value);
   2179    /* initialize the FIPS flag properly */
   2180    sftk_setFIPS(object, sftk_isFIPS(slot->slotID));
   2181    object->objectInfo = NULL;
   2182    object->infoFree = NULL;
   2183    if (!hasLocks) {
   2184        object->refLock = PZ_NewLock(nssILockRefLock);
   2185    }
   2186    if (object->refLock == NULL) {
   2187        goto loser;
   2188    }
   2189    object->refCount = 1;
   2190 
   2191    return object;
   2192 loser:
   2193    (void)sftk_DestroyObject(object);
   2194    return NULL;
   2195 }
   2196 
   2197 SFTKTokenObject *
   2198 sftk_convertSessionToToken(SFTKObject *obj)
   2199 {
   2200    SECItem *key;
   2201    SFTKSessionObject *so = (SFTKSessionObject *)obj;
   2202    SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
   2203    SECStatus rv;
   2204 
   2205    sftk_DestroySessionObjectData(so);
   2206    PZ_DestroyLock(so->attributeLock);
   2207    if (to == NULL) {
   2208        return NULL;
   2209    }
   2210    sftk_tokenKeyLock(so->obj.slot);
   2211    key = sftk_lookupTokenKeyByHandle(so->obj.slot, so->obj.handle);
   2212    if (key == NULL) {
   2213        sftk_tokenKeyUnlock(so->obj.slot);
   2214        return NULL;
   2215    }
   2216    rv = SECITEM_CopyItem(NULL, &to->dbKey, key);
   2217    sftk_tokenKeyUnlock(so->obj.slot);
   2218    if (rv == SECFailure) {
   2219        return NULL;
   2220    }
   2221 
   2222    return to;
   2223 }
   2224 
   2225 SFTKSessionObject *
   2226 sftk_narrowToSessionObject(SFTKObject *obj)
   2227 {
   2228    return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
   2229 }
   2230 
   2231 SFTKTokenObject *
   2232 sftk_narrowToTokenObject(SFTKObject *obj)
   2233 {
   2234    return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
   2235 }
   2236 
   2237 /* Constant time helper functions */
   2238 
   2239 /* sftk_CKRVToMask returns, in constant time, a mask value of
   2240 * all ones if rv == CKR_OK.  Otherwise it returns zero. */
   2241 unsigned int
   2242 sftk_CKRVToMask(CK_RV rv)
   2243 {
   2244    PR_STATIC_ASSERT(CKR_OK == 0);
   2245    return ~PORT_CT_NOT_ZERO(rv);
   2246 }
   2247 
   2248 /* sftk_CheckCBCPadding checks, in constant time, the padding validity and
   2249 * accordingly sets the pad length. */
   2250 CK_RV
   2251 sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen,
   2252                     unsigned int blockSize, unsigned int *outPadSize)
   2253 {
   2254    PORT_Assert(outPadSize);
   2255 
   2256    unsigned int padSize = (unsigned int)pBuf[bufLen - 1];
   2257 
   2258    /* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/
   2259    unsigned int goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(~(blockSize - padSize));
   2260    /* padSize should not be 0 */
   2261    goodPad &= PORT_CT_NOT_ZERO(padSize);
   2262 
   2263    unsigned int i;
   2264    for (i = 0; i < blockSize; i++) {
   2265        /* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/
   2266        unsigned int loopMask = PORT_CT_DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));
   2267        /* Get the padding value (should be padSize) from buffer */
   2268        unsigned int padVal = pBuf[bufLen - 1 - i];
   2269        /* Update goodPad only if i < padSize */
   2270        goodPad &= PORT_CT_SEL(loopMask, ~(padVal ^ padSize), goodPad);
   2271    }
   2272 
   2273    /* If any of the final padding bytes had the wrong value, one or more
   2274     * of the lower eight bits of |goodPad| will be cleared. We AND the
   2275     * bottom 8 bits together and duplicate the result to all the bits. */
   2276    goodPad &= goodPad >> 4;
   2277    goodPad &= goodPad >> 2;
   2278    goodPad &= goodPad >> 1;
   2279    goodPad <<= sizeof(goodPad) * 8 - 1;
   2280    goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(goodPad);
   2281 
   2282    /* Set outPadSize to padSize or 0 */
   2283    *outPadSize = PORT_CT_SEL(goodPad, padSize, 0);
   2284    /* Return OK if the pad is valid */
   2285    return PORT_CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID);
   2286 }
   2287 
   2288 void
   2289 sftk_EncodeInteger(PRUint64 integer, CK_ULONG num_bits, CK_BBOOL littleEndian,
   2290                   CK_BYTE_PTR output, CK_ULONG_PTR output_len)
   2291 {
   2292    if (output_len) {
   2293        *output_len = (num_bits / 8);
   2294    }
   2295 
   2296    PR_ASSERT(num_bits > 0 && num_bits <= 64 && (num_bits % 8) == 0);
   2297 
   2298    if (littleEndian == CK_TRUE) {
   2299        for (size_t offset = 0; offset < num_bits / 8; offset++) {
   2300            output[offset] = (unsigned char)((integer >> (offset * 8)) & 0xFF);
   2301        }
   2302    } else {
   2303        for (size_t offset = 0; offset < num_bits / 8; offset++) {
   2304            PRUint64 shift = num_bits - (offset + 1) * 8;
   2305            output[offset] = (unsigned char)((integer >> shift) & 0xFF);
   2306        }
   2307    }
   2308 }
   2309 
   2310 CK_FLAGS
   2311 sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op)
   2312 {
   2313    CK_FLAGS flags = 0;
   2314 
   2315    switch (op) {
   2316        case CKA_ENCRYPT:
   2317            flags = CKF_ENCRYPT;
   2318            break;
   2319        case CKA_DECRYPT:
   2320            flags = CKF_DECRYPT;
   2321            break;
   2322        case CKA_WRAP:
   2323            flags = CKF_WRAP;
   2324            break;
   2325        case CKA_UNWRAP:
   2326            flags = CKF_UNWRAP;
   2327            break;
   2328        case CKA_SIGN:
   2329            flags = CKF_SIGN;
   2330            break;
   2331        case CKA_SIGN_RECOVER:
   2332            flags = CKF_SIGN_RECOVER;
   2333            break;
   2334        case CKA_VERIFY:
   2335            flags = CKF_VERIFY;
   2336            break;
   2337        case CKA_VERIFY_RECOVER:
   2338            flags = CKF_VERIFY_RECOVER;
   2339            break;
   2340        case CKA_DERIVE:
   2341            flags = CKF_DERIVE;
   2342            break;
   2343        /* fake attribute to select digesting */
   2344        case CKA_DIGEST:
   2345            flags = CKF_DIGEST;
   2346            break;
   2347        case CKA_NSS_MESSAGE | CKA_ENCRYPT:
   2348            flags = CKF_MESSAGE_ENCRYPT;
   2349            break;
   2350        case CKA_NSS_MESSAGE | CKA_DECRYPT:
   2351            flags = CKF_MESSAGE_DECRYPT;
   2352            break;
   2353        case CKA_NSS_MESSAGE | CKA_SIGN:
   2354            flags = CKF_MESSAGE_SIGN;
   2355            break;
   2356        case CKA_NSS_MESSAGE | CKA_VERIFY:
   2357            flags = CKF_MESSAGE_VERIFY;
   2358            break;
   2359        default:
   2360            break;
   2361    }
   2362    return flags;
   2363 }
   2364 
   2365 /*
   2366 * ******************** Hash Utilities **************************
   2367 */
   2368 /*
   2369 * Utility function for converting PSS/OAEP parameter types into
   2370 * HASH_HashTypes. Note: Only SHA family functions are defined in RFC 3447.
   2371 */
   2372 HASH_HashType
   2373 sftk_GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech)
   2374 {
   2375    switch (mech) {
   2376        case CKM_SHA_1:
   2377        case CKG_MGF1_SHA1:
   2378            return HASH_AlgSHA1;
   2379        case CKM_SHA224:
   2380        case CKG_MGF1_SHA224:
   2381            return HASH_AlgSHA224;
   2382        case CKM_SHA256:
   2383        case CKG_MGF1_SHA256:
   2384            return HASH_AlgSHA256;
   2385        case CKM_SHA384:
   2386        case CKG_MGF1_SHA384:
   2387            return HASH_AlgSHA384;
   2388        case CKM_SHA512:
   2389        case CKG_MGF1_SHA512:
   2390            return HASH_AlgSHA512;
   2391        default:
   2392            return HASH_AlgNULL;
   2393    }
   2394 }
   2395 
   2396 #ifdef NSS_HAS_FIPS_INDICATORS
   2397 /**************** FIPS Indicator Utilities *************************/
   2398 /* sigh, we probably need a version of this in secutil so that both
   2399 * softoken and NSS can use it */
   2400 static SECOidTag
   2401 sftk_quickGetECCCurveOid(SFTKObject *source)
   2402 {
   2403    SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS);
   2404    unsigned char *encoded;
   2405    int len;
   2406    SECItem oid;
   2407    SECOidTag tag;
   2408 
   2409    if (attribute == NULL) {
   2410        return SEC_OID_UNKNOWN;
   2411    }
   2412    encoded = attribute->attrib.pValue;
   2413    len = attribute->attrib.ulValueLen;
   2414    if ((len < 2) || (encoded[0] != SEC_ASN1_OBJECT_ID) ||
   2415        (len != encoded[1] + 2)) {
   2416        sftk_FreeAttribute(attribute);
   2417        return SEC_OID_UNKNOWN;
   2418    }
   2419    oid.data = encoded + 2;
   2420    oid.len = len - 2;
   2421    tag = SECOID_FindOIDTag(&oid);
   2422    sftk_FreeAttribute(attribute);
   2423    return tag;
   2424 }
   2425 
   2426 /* This function currently only returns valid lengths for
   2427 * FIPS approved ECC curves. If we want to make this generic
   2428 * in the future, that Curve determination can be done in
   2429 * the sftk_handleSpecial. Since it's currently only used
   2430 * in FIPS indicators, it's currently only compiled with
   2431 * the FIPS indicator code */
   2432 static int
   2433 sftk_getKeyLength(SFTKObject *source)
   2434 {
   2435    CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
   2436    CK_ATTRIBUTE_TYPE keyAttribute;
   2437    CK_ULONG keyLength = 0;
   2438    SFTKAttribute *attribute;
   2439    CK_RV crv;
   2440 
   2441    /* If we don't have a key, then it doesn't have a length.
   2442     * this may be OK (say we are hashing). The mech info will
   2443     * sort this out because algorithms which expect no keys
   2444     * will accept zero length for the keys */
   2445    if (source == NULL) {
   2446        return 0;
   2447    }
   2448 
   2449    crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);
   2450    if (crv != CKR_OK) {
   2451        /* sometimes we're passed a data object, in that case the
   2452         * key length is CKA_VALUE, which is the default */
   2453        keyType = CKK_INVALID_KEY_TYPE;
   2454    }
   2455    if (keyType == CKK_EC) {
   2456        SECOidTag curve = sftk_quickGetECCCurveOid(source);
   2457        switch (curve) {
   2458            case SEC_OID_CURVE25519:
   2459                /* change when we start algorithm testing on curve25519 */
   2460                return 0;
   2461            case SEC_OID_SECG_EC_SECP256R1:
   2462                return 256;
   2463            case SEC_OID_SECG_EC_SECP384R1:
   2464                return 384;
   2465            case SEC_OID_SECG_EC_SECP521R1:
   2466                /* this is a lie, but it makes the table easier. We don't
   2467                 * have to have a double entry for every ECC mechanism */
   2468                return 512;
   2469            default:
   2470                break;
   2471        }
   2472        /* other curves aren't NIST approved, returning 0 will cause these
   2473         * curves to fail FIPS length criteria */
   2474        return 0;
   2475    }
   2476 
   2477    switch (keyType) {
   2478        case CKK_RSA:
   2479            keyAttribute = CKA_MODULUS;
   2480            break;
   2481        case CKK_DSA:
   2482        case CKK_DH:
   2483            keyAttribute = CKA_PRIME;
   2484            break;
   2485        default:
   2486            keyAttribute = CKA_VALUE;
   2487            break;
   2488    }
   2489    attribute = sftk_FindAttribute(source, keyAttribute);
   2490    if (attribute) {
   2491        keyLength = attribute->attrib.ulValueLen * 8;
   2492        sftk_FreeAttribute(attribute);
   2493    }
   2494    return keyLength;
   2495 }
   2496 
   2497 /*
   2498 * handle specialized FIPS semantics that are too complicated to
   2499 * handle with just a table. NOTE: this means any additional semantics
   2500 * would have to be coded here before they can be added to the table */
   2501 static PRBool
   2502 sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech,
   2503                   SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source)
   2504 {
   2505    switch (mechInfo->special) {
   2506        case SFTKFIPSDH: {
   2507            SECItem dhPrime;
   2508            SECItem dhBase;
   2509            SECItem dhGenerator;
   2510            PRBool fipsOk = PR_FALSE;
   2511            const SECItem *dhSubPrime;
   2512            CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
   2513                                               source, CKA_PRIME);
   2514            if (crv != CKR_OK) {
   2515                return PR_FALSE;
   2516            }
   2517            crv = sftk_Attribute2SecItem(NULL, &dhBase, source, CKA_BASE);
   2518            if (crv != CKR_OK) {
   2519                return PR_FALSE;
   2520            }
   2521            dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, &dhGenerator, PR_TRUE);
   2522            fipsOk = (dhSubPrime) ? PR_TRUE : PR_FALSE;
   2523            if (fipsOk && (SECITEM_CompareItem(&dhBase, &dhGenerator) != 0)) {
   2524                fipsOk = PR_FALSE;
   2525            }
   2526 
   2527            SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
   2528            SECITEM_ZfreeItem(&dhBase, PR_FALSE);
   2529            return fipsOk;
   2530        }
   2531        case SFTKFIPSNone:
   2532            return PR_FALSE;
   2533        case SFTKFIPSECC:
   2534            /* we've already handled the curve selection in the 'getlength'
   2535             * function */
   2536            return PR_TRUE;
   2537        case SFTKFIPSAEAD: {
   2538            if (mech->ulParameterLen == 0) {
   2539                /* AEAD ciphers are only in FIPS mode if we are using the
   2540                 * MESSAGE interface. This takes an empty parameter
   2541                 * in the init function */
   2542                return PR_TRUE;
   2543            }
   2544            return PR_FALSE;
   2545        }
   2546        case SFTKFIPSRSAPSS: {
   2547            /* PSS salt must not be longer than the  underlying hash.
   2548             * We verify that the underlying hash of the
   2549             * parameters matches Hash of the combined hash mechanisms, so
   2550             * we don't need to look at the specific PSS mechanism */
   2551            CK_RSA_PKCS_PSS_PARAMS *pss = (CK_RSA_PKCS_PSS_PARAMS *)
   2552                                              mech->pParameter;
   2553            const SECHashObject *hashObj = NULL;
   2554            if (mech->ulParameterLen != sizeof(*pss)) {
   2555                return PR_FALSE;
   2556            }
   2557            /* we use the existing hash utilities to find the length of
   2558             * the hash */
   2559            hashObj = HASH_GetRawHashObject(sftk_GetHashTypeFromMechanism(
   2560                pss->hashAlg));
   2561            if (hashObj == NULL) {
   2562                return PR_FALSE;
   2563            }
   2564            if (pss->sLen > hashObj->length) {
   2565                return PR_FALSE;
   2566            }
   2567            return PR_TRUE;
   2568        }
   2569        default:
   2570            break;
   2571    }
   2572    /* if we didn't understand the special processing, mark it non-fips */
   2573    return PR_FALSE;
   2574 }
   2575 #endif
   2576 
   2577 PRBool
   2578 sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
   2579                     SFTKObject *source)
   2580 {
   2581 #ifndef NSS_HAS_FIPS_INDICATORS
   2582    return PR_FALSE;
   2583 #else
   2584    int i;
   2585    CK_FLAGS opFlags;
   2586    CK_ULONG keyLength;
   2587 
   2588    /* handle all the quick stuff first */
   2589    if (!sftk_isFIPS(slot->slotID)) {
   2590        return PR_FALSE;
   2591    }
   2592    if (source && !sftk_hasFIPS(source)) {
   2593        return PR_FALSE;
   2594    }
   2595    if (mech == NULL) {
   2596        return PR_FALSE;
   2597    }
   2598 
   2599    /* now get the calculated values */
   2600    opFlags = sftk_AttributeToFlags(op);
   2601    if (opFlags == 0) {
   2602        return PR_FALSE;
   2603    }
   2604    keyLength = sftk_getKeyLength(source);
   2605 
   2606    /* check against our algorithm array */
   2607    for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) {
   2608        SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];
   2609        /* if we match the number of records exactly, then we are an
   2610         * approved algorithm in the approved mode with an approved key */
   2611        if (((mech->mechanism == mechs->type) &&
   2612             (opFlags == (mechs->info.flags & opFlags)) &&
   2613             (keyLength <= mechs->info.ulMaxKeySize) &&
   2614             (keyLength >= mechs->info.ulMinKeySize) &&
   2615             ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&
   2616            ((mechs->special == SFTKFIPSNone) ||
   2617             sftk_handleSpecial(slot, mech, mechs, source))) {
   2618            return PR_TRUE;
   2619        }
   2620    }
   2621    return PR_FALSE;
   2622 #endif
   2623 }
   2624 
   2625 void
   2626 sftk_setFIPS(SFTKObject *obj, PRBool isFIPS)
   2627 {
   2628    if (isFIPS) {
   2629        obj->validation_value |= SFTK_VALIDATION_FIPS_FLAG;
   2630    } else {
   2631        obj->validation_value &= ~SFTK_VALIDATION_FIPS_FLAG;
   2632    }
   2633 }
   2634 
   2635 PRBool
   2636 sftk_hasFIPS(SFTKObject *obj)
   2637 {
   2638    return (obj->validation_value & SFTK_VALIDATION_FIPS_FLAG) ? PR_TRUE : PR_FALSE;
   2639 }
   2640 
   2641 /*
   2642 * create the FIPS Validation objects. If the vendor
   2643 * doesn't supply an NSS_FIPS_MODULE_ID, at compile time,
   2644 * then we assumethis is an unvalidated module.
   2645 */
   2646 CK_RV
   2647 sftk_CreateValidationObjects(SFTKSlot *slot)
   2648 {
   2649    const char *module_id;
   2650    int module_id_len;
   2651    CK_RV crv = CKR_OK;
   2652    /* we currently use both vendor specific values and PKCS #11 v3.2
   2653     * values for compatibility for a couple more ESR releases. Then we can
   2654     * drop the vendor specific ones */
   2655    CK_OBJECT_CLASS cko_nss_validation = CKO_NSS_VALIDATION;
   2656    CK_OBJECT_CLASS cko_validation = CKO_VALIDATION;
   2657    CK_NSS_VALIDATION_TYPE ckv_fips = CKV_NSS_FIPS_140;
   2658    CK_FLAGS fipsFlag = SFTK_VALIDATION_FIPS_FLAG;
   2659    CK_VALIDATION_TYPE swValidationType = CKV_TYPE_SOFTWARE;
   2660    CK_VALIDATION_AUTHORITY_TYPE nistValidationAuthority =
   2661        CKV_AUTHORITY_TYPE_NIST_CMVP;
   2662    CK_UTF8CHAR us[] = { 'U', 'S' };
   2663    CK_VERSION fips_version = { 3, 0 }; /* FIPS-140-3 */
   2664    CK_ULONG fips_level = 1;            /* or 2 if you validated at level 2 */
   2665 
   2666 #ifndef NSS_FIPS_MODULE_ID
   2667 #define NSS_FIPS_MODULE_ID "Generic NSS " SOFTOKEN_VERSION " Unvalidated"
   2668 #endif
   2669    module_id = NSS_FIPS_MODULE_ID;
   2670    module_id_len = sizeof(NSS_FIPS_MODULE_ID) - 1;
   2671    SFTKObject *object;
   2672 
   2673    object = sftk_NewObject(slot); /* fill in the handle later */
   2674    if (object == NULL) {
   2675        return CKR_HOST_MEMORY;
   2676    }
   2677    sftk_setFIPS(object, PR_FALSE);
   2678 
   2679    crv = sftk_AddAttributeType(object, CKA_CLASS, &cko_nss_validation,
   2680                                sizeof(cko_nss_validation));
   2681    if (crv != CKR_OK) {
   2682        goto loser;
   2683    }
   2684    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_TYPE,
   2685                                &ckv_fips, sizeof(ckv_fips));
   2686    if (crv != CKR_OK) {
   2687        goto loser;
   2688    }
   2689    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_VERSION,
   2690                                &fips_version, sizeof(fips_version));
   2691    if (crv != CKR_OK) {
   2692        goto loser;
   2693    }
   2694    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_LEVEL,
   2695                                &fips_level, sizeof(fips_level));
   2696    if (crv != CKR_OK) {
   2697        goto loser;
   2698    }
   2699    crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_MODULE_ID,
   2700                                module_id, module_id_len);
   2701    if (crv != CKR_OK) {
   2702        goto loser;
   2703    }
   2704 
   2705    object->handle = sftk_getNextHandle(slot);
   2706    object->slot = slot;
   2707    sftk_AddObject(&slot->moduleObjects, object);
   2708    sftk_FreeObject(object);
   2709 
   2710    object = sftk_NewObject(slot); /* fill in the handle later */
   2711    if (object == NULL) {
   2712        return CKR_HOST_MEMORY;
   2713    }
   2714    sftk_setFIPS(object, PR_FALSE);
   2715    crv = sftk_AddAttributeType(object, CKA_CLASS, &cko_validation,
   2716                                sizeof(cko_validation));
   2717    if (crv != CKR_OK) {
   2718        goto loser;
   2719    }
   2720    crv = sftk_AddAttributeType(object, CKA_VALIDATION_TYPE,
   2721                                &swValidationType, sizeof(swValidationType));
   2722    if (crv != CKR_OK) {
   2723        goto loser;
   2724    }
   2725    crv = sftk_AddAttributeType(object, CKA_VALIDATION_VERSION,
   2726                                &fips_version, sizeof(fips_version));
   2727    if (crv != CKR_OK) {
   2728        goto loser;
   2729    }
   2730    crv = sftk_AddAttributeType(object, CKA_VALIDATION_LEVEL,
   2731                                &fips_level, sizeof(fips_level));
   2732    if (crv != CKR_OK) {
   2733        goto loser;
   2734    }
   2735    crv = sftk_AddAttributeType(object, CKA_VALIDATION_MODULE_ID,
   2736                                module_id, module_id_len);
   2737    if (crv != CKR_OK) {
   2738        goto loser;
   2739    }
   2740    crv = sftk_AddAttributeType(object, CKA_VALIDATION_FLAG,
   2741                                &fipsFlag, sizeof(fipsFlag));
   2742    if (crv != CKR_OK) {
   2743        goto loser;
   2744    }
   2745    crv = sftk_AddAttributeType(object, CKA_VALIDATION_AUTHORITY_TYPE,
   2746                                &nistValidationAuthority,
   2747                                sizeof(nistValidationAuthority));
   2748    if (crv != CKR_OK) {
   2749        goto loser;
   2750    }
   2751    crv = sftk_AddAttributeType(object, CKA_VALIDATION_COUNTRY, us, sizeof(us));
   2752    if (crv != CKR_OK) {
   2753        goto loser;
   2754    }
   2755    crv = sftk_AddAttributeType(object, CKA_VALIDATION_CERTIFICATE_IDENTIFIER,
   2756                                NULL, 0);
   2757    if (crv != CKR_OK) {
   2758        goto loser;
   2759    }
   2760    crv = sftk_AddAttributeType(object, CKA_VALIDATION_CERTIFICATE_URI,
   2761                                NULL, 0);
   2762    if (crv != CKR_OK) {
   2763        goto loser;
   2764    }
   2765    crv = sftk_AddAttributeType(object, CKA_VALIDATION_PROFILE,
   2766                                NULL, 0);
   2767    if (crv != CKR_OK) {
   2768        goto loser;
   2769    }
   2770    crv = sftk_AddAttributeType(object, CKA_VALIDATION_VENDOR_URI,
   2771                                NULL, 0);
   2772    if (crv != CKR_OK) {
   2773        goto loser;
   2774    }
   2775    /* future, fill in validation certificate information from a supplied
   2776     * pointer to a config file */
   2777    object->handle = sftk_getNextHandle(slot);
   2778    object->slot = slot;
   2779    sftk_AddObject(&slot->moduleObjects, object);
   2780 loser:
   2781    sftk_FreeObject(object);
   2782 
   2783    return crv;
   2784 }