Coverage Report

Created: 2026-10-13 06:23

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