Coverage Report

Created: 2026-06-07 07:11

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