Coverage Report

Created: 2025-04-22 06:15

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