Coverage Report

Created: 2025-08-18 06:35

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