Coverage Report

Created: 2026-10-13 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/dev/devutil.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
#ifndef DEVM_H
6
#include "devm.h"
7
#endif /* DEVM_H */
8
9
#ifndef CKHELPER_H
10
#include "ckhelper.h"
11
#endif /* CKHELPER_H */
12
13
#include "pk11pub.h"
14
#include "dev3hack.h"
15
#include "secerr.h"
16
17
NSS_IMPLEMENT nssCryptokiObject *
18
nssCryptokiObject_Create(
19
    NSSToken *t,
20
    nssSession *session,
21
    CK_OBJECT_HANDLE h)
22
4
{
23
4
    PRStatus status;
24
4
    NSSSlot *slot;
25
4
    nssCryptokiObject *object;
26
4
    CK_BBOOL *isTokenObject;
27
4
    CK_ATTRIBUTE cert_template[] = {
28
4
        { CKA_TOKEN, NULL, 0 },
29
4
        { CKA_LABEL, NULL, 0 }
30
4
    };
31
4
    slot = nssToken_GetSlot(t);
32
4
    status = nssCKObject_GetAttributes(h, cert_template, 2,
33
4
                                       NULL, session, slot);
34
4
    nssSlot_Destroy(slot);
35
4
    if (status != PR_SUCCESS) {
36
        /* a failure here indicates a device error */
37
0
        return (nssCryptokiObject *)NULL;
38
0
    }
39
4
    if (cert_template[0].ulValueLen == 0 || !cert_template[0].pValue) {
40
0
        nss_ZFreeIf(cert_template[1].pValue);
41
0
        return (nssCryptokiObject *)NULL;
42
0
    }
43
4
    object = nss_ZNEW(NULL, nssCryptokiObject);
44
4
    if (!object) {
45
0
        nss_ZFreeIf(cert_template[0].pValue);
46
0
        nss_ZFreeIf(cert_template[1].pValue);
47
0
        return (nssCryptokiObject *)NULL;
48
0
    }
49
4
    object->handle = h;
50
4
    object->token = nssToken_AddRef(t);
51
4
    isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
52
4
    object->isTokenObject = *isTokenObject;
53
4
    object->trustType = CKM_INVALID_MECHANISM;
54
4
    nss_ZFreeIf(cert_template[0].pValue);
55
4
    NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
56
4
    return object;
57
4
}
58
59
NSS_IMPLEMENT void
60
nssCryptokiObject_Destroy(
61
    nssCryptokiObject *object)
62
22
{
63
22
    if (object) {
64
22
        (void)nssToken_Destroy(object->token);
65
22
        nss_ZFreeIf(object->label);
66
22
        nss_ZFreeIf(object);
67
22
    }
68
22
}
69
70
NSS_IMPLEMENT nssCryptokiObject *
71
nssCryptokiObject_Clone(
72
    nssCryptokiObject *object)
73
16
{
74
16
    nssCryptokiObject *rvObject;
75
16
    rvObject = nss_ZNEW(NULL, nssCryptokiObject);
76
16
    if (rvObject) {
77
16
        rvObject->handle = object->handle;
78
16
        rvObject->token = nssToken_AddRef(object->token);
79
16
        rvObject->isTokenObject = object->isTokenObject;
80
16
        if (object->label) {
81
16
            rvObject->label = nssUTF8_Duplicate(object->label, NULL);
82
16
        }
83
16
    }
84
16
    return rvObject;
85
16
}
86
87
NSS_EXTERN PRBool
88
nssCryptokiObject_Equal(
89
    nssCryptokiObject *o1,
90
    nssCryptokiObject *o2)
91
1
{
92
1
    return (o1->token == o2->token && o1->handle == o2->handle);
93
1
}
94
95
/*
96
 * Slot arrays
97
 */
98
99
NSS_IMPLEMENT void
100
nssSlotArray_Destroy(
101
    NSSSlot **slots)
102
346k
{
103
346k
    if (slots) {
104
346k
        NSSSlot **slotp;
105
1.03M
        for (slotp = slots; *slotp; slotp++) {
106
692k
            nssSlot_Destroy(*slotp);
107
692k
        }
108
346k
        nss_ZFreeIf(slots);
109
346k
    }
110
346k
}
111
112
NSS_IMPLEMENT void
113
nssTokenArray_Destroy(
114
    NSSToken **tokens)
115
0
{
116
0
    if (tokens) {
117
0
        NSSToken **tokenp;
118
0
        for (tokenp = tokens; *tokenp; tokenp++) {
119
0
            (void)nssToken_Destroy(*tokenp);
120
0
        }
121
0
        nss_ZFreeIf(tokens);
122
0
    }
123
0
}
124
125
NSS_IMPLEMENT void
126
nssCryptokiObjectArray_Destroy(
127
    nssCryptokiObject **objects)
128
12
{
129
12
    if (objects) {
130
12
        nssCryptokiObject **op;
131
24
        for (op = objects; *op; op++) {
132
12
            nssCryptokiObject_Destroy(*op);
133
12
        }
134
12
        nss_ZFreeIf(objects);
135
12
    }
136
12
}
137
138
/* object cache for token */
139
140
typedef struct
141
{
142
    NSSArena *arena;
143
    nssCryptokiObject *object;
144
    CK_ATTRIBUTE_PTR attributes;
145
    CK_ULONG numAttributes;
146
} nssCryptokiObjectAndAttributes;
147
148
enum {
149
    cachedCerts = 0,
150
    cachedTrust = 1,
151
    cachedCRLs = 2
152
} cachedObjectType;
153
154
struct nssTokenObjectCacheStr {
155
    NSSToken *token;
156
    PRLock *lock;
157
    PRBool loggedIn;
158
    PRBool doObjectType[3];
159
    PRBool searchedObjectType[3];
160
    nssCryptokiObjectAndAttributes **objects[3];
161
};
162
163
NSS_IMPLEMENT nssTokenObjectCache *
164
nssTokenObjectCache_Create(
165
    NSSToken *token,
166
    PRBool cacheCerts,
167
    PRBool cacheTrust,
168
    PRBool cacheCRLs)
169
0
{
170
0
    nssTokenObjectCache *rvCache;
171
0
    rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
172
0
    if (!rvCache) {
173
0
        goto loser;
174
0
    }
175
0
    rvCache->lock = PR_NewLock(); /* XXX */
176
0
    if (!rvCache->lock) {
177
0
        goto loser;
178
0
    }
179
0
    rvCache->doObjectType[cachedCerts] = cacheCerts;
180
0
    rvCache->doObjectType[cachedTrust] = cacheTrust;
181
0
    rvCache->doObjectType[cachedCRLs] = cacheCRLs;
182
0
    rvCache->token = token; /* cache goes away with token */
183
0
    return rvCache;
184
0
loser:
185
0
    nssTokenObjectCache_Destroy(rvCache);
186
0
    return (nssTokenObjectCache *)NULL;
187
0
}
188
189
static void
190
clear_cache(
191
    nssTokenObjectCache *cache)
192
0
{
193
0
    nssCryptokiObjectAndAttributes **oa;
194
0
    PRUint32 objectType;
195
0
    for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
196
0
        cache->searchedObjectType[objectType] = PR_FALSE;
197
0
        if (!cache->objects[objectType]) {
198
0
            continue;
199
0
        }
200
0
        for (oa = cache->objects[objectType]; *oa; oa++) {
201
            /* prevent the token from being destroyed */
202
0
            (*oa)->object->token = NULL;
203
0
            nssCryptokiObject_Destroy((*oa)->object);
204
0
            nssArena_Destroy((*oa)->arena);
205
0
        }
206
0
        nss_ZFreeIf(cache->objects[objectType]);
207
0
        cache->objects[objectType] = NULL;
208
0
    }
209
0
}
210
211
NSS_IMPLEMENT void
212
nssTokenObjectCache_Clear(
213
    nssTokenObjectCache *cache)
214
0
{
215
0
    if (cache) {
216
0
        PR_Lock(cache->lock);
217
0
        clear_cache(cache);
218
0
        PR_Unlock(cache->lock);
219
0
    }
220
0
}
221
222
NSS_IMPLEMENT void
223
nssTokenObjectCache_Destroy(
224
    nssTokenObjectCache *cache)
225
32
{
226
32
    if (cache) {
227
0
        clear_cache(cache);
228
0
        if (cache->lock) {
229
0
            PR_DestroyLock(cache->lock);
230
0
        }
231
0
        nss_ZFreeIf(cache);
232
0
    }
233
32
}
234
235
NSS_IMPLEMENT PRBool
236
nssTokenObjectCache_HaveObjectClass(
237
    nssTokenObjectCache *cache,
238
    CK_OBJECT_CLASS objclass)
239
0
{
240
0
    PRBool haveIt;
241
0
    PR_Lock(cache->lock);
242
0
    switch (objclass) {
243
0
        case CKO_CERTIFICATE:
244
0
            haveIt = cache->doObjectType[cachedCerts];
245
0
            break;
246
0
        case CKO_NSS_TRUST:
247
0
        case CKO_TRUST:
248
0
            haveIt = cache->doObjectType[cachedTrust];
249
0
            break;
250
0
        case CKO_NSS_CRL:
251
0
            haveIt = cache->doObjectType[cachedCRLs];
252
0
            break;
253
0
        default:
254
0
            haveIt = PR_FALSE;
255
0
    }
256
0
    PR_Unlock(cache->lock);
257
0
    return haveIt;
258
0
}
259
260
static nssCryptokiObjectAndAttributes **
261
create_object_array(
262
    nssCryptokiObject **objects,
263
    PRBool *doObjects,
264
    PRUint32 *numObjects,
265
    PRStatus *status)
266
0
{
267
0
    nssCryptokiObjectAndAttributes **rvOandA = NULL;
268
0
    *numObjects = 0;
269
    /* There are no objects for this type */
270
0
    if (!objects || !*objects) {
271
0
        *status = PR_SUCCESS;
272
0
        return rvOandA;
273
0
    }
274
0
    while (*objects++)
275
0
        (*numObjects)++;
276
0
    if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
277
        /* Hit the maximum allowed, so don't use a cache (there are
278
         * too many objects to make caching worthwhile, presumably, if
279
         * the token can handle that many objects, it can handle searching.
280
         */
281
0
        *doObjects = PR_FALSE;
282
0
        *status = PR_FAILURE;
283
0
        *numObjects = 0;
284
0
    } else {
285
0
        rvOandA = nss_ZNEWARRAY(NULL,
286
0
                                nssCryptokiObjectAndAttributes *,
287
0
                                *numObjects + 1);
288
0
        *status = rvOandA ? PR_SUCCESS : PR_FAILURE;
289
0
    }
290
0
    return rvOandA;
291
0
}
292
293
static nssCryptokiObjectAndAttributes *
294
create_object(
295
    nssCryptokiObject *object,
296
    const CK_ATTRIBUTE_TYPE *types,
297
    PRUint32 numTypes,
298
    PRStatus *status)
299
0
{
300
0
    PRUint32 j;
301
0
    NSSArena *arena = NULL;
302
0
    NSSSlot *slot = NULL;
303
0
    nssSession *session = NULL;
304
0
    nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
305
306
0
    slot = nssToken_GetSlot(object->token);
307
0
    if (!slot) {
308
0
        nss_SetError(NSS_ERROR_INVALID_POINTER);
309
0
        goto loser;
310
0
    }
311
0
    session = nssToken_GetDefaultSession(object->token);
312
0
    if (!session) {
313
0
        nss_SetError(NSS_ERROR_INVALID_POINTER);
314
0
        goto loser;
315
0
    }
316
0
    arena = nssArena_Create();
317
0
    if (!arena) {
318
0
        goto loser;
319
0
    }
320
0
    rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
321
0
    if (!rvCachedObject) {
322
0
        goto loser;
323
0
    }
324
0
    rvCachedObject->arena = arena;
325
0
    rvCachedObject->object = object;
326
0
    rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
327
0
    if (!rvCachedObject->attributes) {
328
0
        goto loser;
329
0
    }
330
0
    for (j = 0; j < numTypes; j++) {
331
0
        rvCachedObject->attributes[j].type = types[j];
332
0
    }
333
0
    *status = nssCKObject_GetAttributes(object->handle,
334
0
                                        rvCachedObject->attributes,
335
0
                                        numTypes,
336
0
                                        arena,
337
0
                                        session,
338
0
                                        slot);
339
0
    if (*status != PR_SUCCESS) {
340
0
        goto loser;
341
0
    }
342
0
    rvCachedObject->numAttributes = numTypes;
343
0
    *status = PR_SUCCESS;
344
0
    nssSlot_Destroy(slot);
345
346
    /* The cache is tied to the token, and therefore the objects in it should
347
     * not hold references to the token. Drop the object's token reference
348
     * only after success so that on failure the caller can still safely
349
     * destroy the object (and its token reference) exactly once.
350
     */
351
0
    (void)nssToken_Destroy(object->token);
352
0
    return rvCachedObject;
353
0
loser:
354
0
    *status = PR_FAILURE;
355
0
    if (slot) {
356
0
        nssSlot_Destroy(slot);
357
0
    }
358
0
    if (arena)
359
0
        nssArena_Destroy(arena);
360
0
    return (nssCryptokiObjectAndAttributes *)NULL;
361
0
}
362
363
/*
364
 *
365
 * State diagram for cache:
366
 *
367
 *            token !present            token removed
368
 *        +-------------------------+<----------------------+
369
 *        |                         ^                       |
370
 *        v                         |                       |
371
 *  +----------+   slot friendly    |  token present   +----------+
372
 *  |   cache  | -----------------> % ---------------> |   cache  |
373
 *  | unloaded |                                       |  loaded  |
374
 *  +----------+                                       +----------+
375
 *    ^   |                                                 ^   |
376
 *    |   |   slot !friendly           slot logged in       |   |
377
 *    |   +-----------------------> % ----------------------+   |
378
 *    |                             |                           |
379
 *    | slot logged out             v  slot !friendly           |
380
 *    +-----------------------------+<--------------------------+
381
 *
382
 */
383
384
/* This function must not be called with cache->lock locked. */
385
static PRBool
386
token_is_present(
387
    nssTokenObjectCache *cache)
388
0
{
389
0
    NSSSlot *slot = nssToken_GetSlot(cache->token);
390
0
    PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
391
0
    nssSlot_Destroy(slot);
392
0
    return tokenPresent;
393
0
}
394
395
static PRBool
396
search_for_objects(
397
    nssTokenObjectCache *cache)
398
0
{
399
0
    PRBool doSearch = PR_FALSE;
400
0
    NSSSlot *slot = nssToken_GetSlot(cache->token);
401
    /* Handle non-friendly slots (slots which require login for objects) */
402
0
    if (!nssSlot_IsFriendly(slot)) {
403
0
        if (nssSlot_IsLoggedIn(slot)) {
404
            /* Either no state change, or went from !logged in -> logged in */
405
0
            cache->loggedIn = PR_TRUE;
406
0
            doSearch = PR_TRUE;
407
0
        } else {
408
0
            if (cache->loggedIn) {
409
                /* went from logged in -> !logged in, destroy cached objects */
410
0
                clear_cache(cache);
411
0
                cache->loggedIn = PR_FALSE;
412
0
            } /* else no state change, still not logged in, so exit */
413
0
        }
414
0
    } else {
415
        /* slot is friendly, thus always available for search */
416
0
        doSearch = PR_TRUE;
417
0
    }
418
0
    nssSlot_Destroy(slot);
419
0
    return doSearch;
420
0
}
421
422
static nssCryptokiObjectAndAttributes *
423
create_cert(
424
    nssCryptokiObject *object,
425
    PRStatus *status)
426
0
{
427
0
    static const CK_ATTRIBUTE_TYPE certAttr[] = {
428
0
        CKA_CLASS,
429
0
        CKA_TOKEN,
430
0
        CKA_LABEL,
431
0
        CKA_CERTIFICATE_TYPE,
432
0
        CKA_ID,
433
0
        CKA_VALUE,
434
0
        CKA_ISSUER,
435
0
        CKA_SERIAL_NUMBER,
436
0
        CKA_SUBJECT,
437
0
        CKA_NSS_EMAIL
438
0
    };
439
0
    static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
440
0
    return create_object(object, certAttr, numCertAttr, status);
441
0
}
442
443
static nssCryptokiObjectAndAttributes *
444
create_trust(
445
    nssCryptokiObject *object,
446
    PRStatus *status)
447
0
{
448
0
    static const CK_ATTRIBUTE_TYPE nssTrustAttr[] = {
449
0
        CKA_CLASS,
450
0
        CKA_TOKEN,
451
0
        CKA_LABEL,
452
0
        CKA_NSS_CERT_SHA1_HASH,
453
0
        CKA_NSS_CERT_MD5_HASH,
454
0
        CKA_ISSUER,
455
0
        CKA_SUBJECT,
456
0
        CKA_NSS_TRUST_SERVER_AUTH,
457
0
        CKA_NSS_TRUST_CLIENT_AUTH,
458
0
        CKA_NSS_TRUST_EMAIL_PROTECTION,
459
0
        CKA_NSS_TRUST_CODE_SIGNING
460
0
    };
461
0
    static const CK_ATTRIBUTE_TYPE pkcsTrustAttr[] = {
462
0
        CKA_CLASS,
463
0
        CKA_TOKEN,
464
0
        CKA_LABEL,
465
0
        CKA_HASH_OF_CERTIFICATE,
466
0
        CKA_NAME_HASH_ALGORITHM,
467
0
        CKA_ISSUER,
468
0
        CKA_SUBJECT,
469
0
        CKA_PKCS_TRUST_SERVER_AUTH,
470
0
        CKA_PKCS_TRUST_CLIENT_AUTH,
471
0
        CKA_PKCS_TRUST_EMAIL_PROTECTION,
472
0
        CKA_PKCS_TRUST_CODE_SIGNING
473
0
    };
474
0
    static const PRUint32 numNSSTrustAttr = PR_ARRAY_SIZE(nssTrustAttr);
475
0
    static const PRUint32 numPKCSTrustAttr = PR_ARRAY_SIZE(pkcsTrustAttr);
476
0
    const CK_ATTRIBUTE_TYPE *trustAttr;
477
0
    PRUint32 numTrustAttr;
478
479
0
    trustAttr = (object->trustType == CKO_TRUST) ? pkcsTrustAttr
480
0
                                                 : nssTrustAttr;
481
0
    numTrustAttr = (object->trustType == CKO_TRUST) ? numPKCSTrustAttr
482
0
                                                    : numNSSTrustAttr;
483
0
    return create_object(object, trustAttr, numTrustAttr, status);
484
0
}
485
486
static nssCryptokiObjectAndAttributes *
487
create_crl(
488
    nssCryptokiObject *object,
489
    PRStatus *status)
490
0
{
491
0
    static const CK_ATTRIBUTE_TYPE crlAttr[] = {
492
0
        CKA_CLASS,
493
0
        CKA_TOKEN,
494
0
        CKA_LABEL,
495
0
        CKA_VALUE,
496
0
        CKA_SUBJECT,
497
0
        CKA_NSS_KRL,
498
0
        CKA_NSS_URL
499
0
    };
500
0
    static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
501
0
    return create_object(object, crlAttr, numCRLAttr, status);
502
0
}
503
504
/* Dispatch to the create function for the object type */
505
static nssCryptokiObjectAndAttributes *
506
create_object_of_type(
507
    nssCryptokiObject *object,
508
    PRUint32 objectType,
509
    PRStatus *status)
510
0
{
511
0
    if (objectType == cachedCerts) {
512
0
        return create_cert(object, status);
513
0
    }
514
0
    if (objectType == cachedTrust) {
515
0
        return create_trust(object, status);
516
0
    }
517
0
    if (objectType == cachedCRLs) {
518
0
        return create_crl(object, status);
519
0
    }
520
0
    return (nssCryptokiObjectAndAttributes *)NULL;
521
0
}
522
523
static PRStatus
524
get_token_objects_for_cache(
525
    nssTokenObjectCache *cache,
526
    PRUint32 objectType,
527
    CK_OBJECT_CLASS objclass)
528
0
{
529
0
    PRStatus status;
530
0
    nssCryptokiObject **objects;
531
0
    PRBool *doIt = &cache->doObjectType[objectType];
532
0
    PRUint32 i, numObjects;
533
534
0
    if (!search_for_objects(cache) ||
535
0
        cache->searchedObjectType[objectType] ||
536
0
        !cache->doObjectType[objectType]) {
537
        /* Either there was a state change that prevents a search
538
         * (token logged out), or the search was already done,
539
         * or objects of this type are not being cached.
540
         */
541
0
        return PR_SUCCESS;
542
0
    }
543
0
    objects = nssToken_FindObjects(cache->token, NULL, objclass,
544
0
                                   nssTokenSearchType_TokenForced,
545
0
                                   MAX_LOCAL_CACHE_OBJECTS, &status);
546
0
    if (status != PR_SUCCESS) {
547
0
        return status;
548
0
    }
549
0
    cache->objects[objectType] = create_object_array(objects,
550
0
                                                     doIt,
551
0
                                                     &numObjects,
552
0
                                                     &status);
553
0
    if (status != PR_SUCCESS) {
554
0
        nssCryptokiObjectArray_Destroy(objects);
555
0
        return status;
556
0
    }
557
0
    for (i = 0; i < numObjects; i++) {
558
0
        cache->objects[objectType][i] = create_object_of_type(objects[i],
559
0
                                                              objectType,
560
0
                                                              &status);
561
0
        if (status != PR_SUCCESS) {
562
0
            break;
563
0
        }
564
0
    }
565
0
    if (status == PR_SUCCESS) {
566
0
        nss_ZFreeIf(objects);
567
0
    } else {
568
0
        PRUint32 j;
569
0
        for (j = 0; j < i; j++) {
570
            /* Objects that were successfully added to the cache do not own a
571
             * token reference (they share a reference with the cache itself).
572
             * Nulling out the pointer here prevents the token's refcount
573
             * from being decremented in nssCryptokiObject_Destroy */
574
0
            cache->objects[objectType][j]->object->token = NULL;
575
0
            nssArena_Destroy(cache->objects[objectType][j]->arena);
576
0
        }
577
0
        nss_ZFreeIf(cache->objects[objectType]);
578
0
        cache->objects[objectType] = NULL;
579
0
        nssCryptokiObjectArray_Destroy(objects);
580
0
    }
581
0
    cache->searchedObjectType[objectType] = PR_TRUE;
582
0
    return status;
583
0
}
584
585
static CK_ATTRIBUTE_PTR
586
find_attribute_in_object(
587
    nssCryptokiObjectAndAttributes *obj,
588
    CK_ATTRIBUTE_TYPE attrType)
589
0
{
590
0
    PRUint32 j;
591
0
    for (j = 0; j < obj->numAttributes; j++) {
592
0
        if (attrType == obj->attributes[j].type) {
593
0
            return &obj->attributes[j];
594
0
        }
595
0
    }
596
0
    return (CK_ATTRIBUTE_PTR)NULL;
597
0
}
598
599
/* Find all objects in the array that match the supplied template */
600
static nssCryptokiObject **
601
find_objects_in_array(
602
    nssCryptokiObjectAndAttributes **objArray,
603
    CK_ATTRIBUTE_PTR ot,
604
    CK_ULONG otlen,
605
    PRUint32 maximumOpt)
606
0
{
607
0
    PRIntn oi = 0;
608
0
    PRUint32 i;
609
0
    NSSArena *arena;
610
0
    PRUint32 size = 8;
611
0
    PRUint32 numMatches = 0;
612
0
    nssCryptokiObject **objects = NULL;
613
0
    nssCryptokiObjectAndAttributes **matches = NULL;
614
0
    CK_ATTRIBUTE_PTR attr;
615
616
0
    if (!objArray) {
617
0
        return (nssCryptokiObject **)NULL;
618
0
    }
619
0
    arena = nssArena_Create();
620
0
    if (!arena) {
621
0
        return (nssCryptokiObject **)NULL;
622
0
    }
623
0
    matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
624
0
    if (!matches) {
625
0
        goto loser;
626
0
    }
627
0
    if (maximumOpt == 0)
628
0
        maximumOpt = ~0;
629
    /* loop over the cached objects */
630
0
    for (; *objArray && numMatches < maximumOpt; objArray++) {
631
0
        nssCryptokiObjectAndAttributes *obj = *objArray;
632
        /* loop over the test template */
633
0
        for (i = 0; i < otlen; i++) {
634
            /* see if the object has the attribute */
635
0
            attr = find_attribute_in_object(obj, ot[i].type);
636
0
            if (!attr) {
637
                /* nope, match failed */
638
0
                break;
639
0
            }
640
            /* compare the attribute against the test value */
641
0
            if (ot[i].ulValueLen != attr->ulValueLen ||
642
0
                !nsslibc_memequal(ot[i].pValue,
643
0
                                  attr->pValue,
644
0
                                  attr->ulValueLen, NULL)) {
645
                /* nope, match failed */
646
0
                break;
647
0
            }
648
0
        }
649
0
        if (i == otlen) {
650
            /* all of the attributes in the test template were found
651
             * in the object's template, and they all matched
652
             */
653
0
            matches[numMatches++] = obj;
654
0
            if (numMatches == size) {
655
0
                size *= 2;
656
0
                matches = nss_ZREALLOCARRAY(matches,
657
0
                                            nssCryptokiObjectAndAttributes *,
658
0
                                            size);
659
0
                if (!matches) {
660
0
                    goto loser;
661
0
                }
662
0
            }
663
0
        }
664
0
    }
665
0
    if (numMatches > 0) {
666
0
        objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
667
0
        if (!objects) {
668
0
            goto loser;
669
0
        }
670
0
        for (oi = 0; oi < (PRIntn)numMatches; oi++) {
671
0
            objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
672
0
            if (!objects[oi]) {
673
0
                goto loser;
674
0
            }
675
0
        }
676
0
    }
677
0
    nssArena_Destroy(arena);
678
0
    return objects;
679
0
loser:
680
0
    nssCryptokiObjectArray_Destroy(objects);
681
0
    nssArena_Destroy(arena);
682
0
    return (nssCryptokiObject **)NULL;
683
0
}
684
685
NSS_IMPLEMENT nssCryptokiObject **
686
nssTokenObjectCache_FindObjectsByTemplate(
687
    nssTokenObjectCache *cache,
688
    CK_OBJECT_CLASS objclass,
689
    CK_ATTRIBUTE_PTR otemplate,
690
    CK_ULONG otlen,
691
    PRUint32 maximumOpt,
692
    PRStatus *statusOpt)
693
0
{
694
0
    PRStatus status = PR_FAILURE;
695
0
    nssCryptokiObject **rvObjects = NULL;
696
0
    PRUint32 objectType;
697
0
    if (!token_is_present(cache)) {
698
0
        status = PR_SUCCESS;
699
0
        goto finish;
700
0
    }
701
0
    switch (objclass) {
702
0
        case CKO_CERTIFICATE:
703
0
            objectType = cachedCerts;
704
0
            break;
705
0
        case CKO_NSS_TRUST:
706
0
        case CKO_TRUST:
707
0
            objectType = cachedTrust;
708
0
            break;
709
0
        case CKO_NSS_CRL:
710
0
            objectType = cachedCRLs;
711
0
            break;
712
0
        default:
713
0
            goto finish;
714
0
    }
715
0
    PR_Lock(cache->lock);
716
0
    if (cache->doObjectType[objectType]) {
717
0
        status = get_token_objects_for_cache(cache, objectType, objclass);
718
0
        if (status == PR_SUCCESS) {
719
0
            rvObjects = find_objects_in_array(cache->objects[objectType],
720
0
                                              otemplate, otlen, maximumOpt);
721
0
        }
722
0
    }
723
0
    PR_Unlock(cache->lock);
724
0
finish:
725
0
    if (statusOpt) {
726
0
        *statusOpt = status;
727
0
    }
728
0
    return rvObjects;
729
0
}
730
731
static PRBool
732
cache_available_for_object_type(
733
    nssTokenObjectCache *cache,
734
    PRUint32 objectType)
735
0
{
736
0
    if (!cache->doObjectType[objectType]) {
737
        /* not caching this object kind */
738
0
        return PR_FALSE;
739
0
    }
740
0
    if (!cache->searchedObjectType[objectType]) {
741
        /* objects are not cached yet */
742
0
        return PR_FALSE;
743
0
    }
744
0
    if (!search_for_objects(cache)) {
745
        /* not logged in */
746
0
        return PR_FALSE;
747
0
    }
748
0
    return PR_TRUE;
749
0
}
750
751
NSS_IMPLEMENT PRStatus
752
nssTokenObjectCache_GetObjectAttributes(
753
    nssTokenObjectCache *cache,
754
    NSSArena *arenaOpt,
755
    nssCryptokiObject *object,
756
    CK_OBJECT_CLASS objclass,
757
    CK_ATTRIBUTE_PTR atemplate,
758
    CK_ULONG atlen)
759
0
{
760
0
    PRUint32 i, j;
761
0
    NSSArena *arena = NULL;
762
0
    nssArenaMark *mark = NULL;
763
0
    nssCryptokiObjectAndAttributes *cachedOA = NULL;
764
0
    nssCryptokiObjectAndAttributes **oa = NULL;
765
0
    PRUint32 objectType;
766
0
    if (!token_is_present(cache)) {
767
0
        return PR_FAILURE;
768
0
    }
769
0
    PR_Lock(cache->lock);
770
0
    switch (objclass) {
771
0
        case CKO_CERTIFICATE:
772
0
            objectType = cachedCerts;
773
0
            break;
774
0
        case CKO_NSS_TRUST:
775
0
        case CKO_TRUST:
776
0
            objectType = cachedTrust;
777
0
            break;
778
0
        case CKO_NSS_CRL:
779
0
            objectType = cachedCRLs;
780
0
            break;
781
0
        default:
782
0
            goto loser;
783
0
    }
784
0
    if (!cache_available_for_object_type(cache, objectType)) {
785
0
        goto loser;
786
0
    }
787
0
    oa = cache->objects[objectType];
788
0
    if (!oa) {
789
0
        goto loser;
790
0
    }
791
0
    for (; *oa; oa++) {
792
0
        if (nssCryptokiObject_Equal((*oa)->object, object)) {
793
0
            cachedOA = *oa;
794
0
            break;
795
0
        }
796
0
    }
797
0
    if (!cachedOA) {
798
0
        goto loser; /* don't have this object */
799
0
    }
800
0
    if (arenaOpt) {
801
0
        arena = arenaOpt;
802
0
        mark = nssArena_Mark(arena);
803
0
    }
804
0
    for (i = 0; i < atlen; i++) {
805
0
        for (j = 0; j < cachedOA->numAttributes; j++) {
806
0
            if (atemplate[i].type == cachedOA->attributes[j].type) {
807
0
                CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
808
0
                if (cachedOA->attributes[j].ulValueLen == 0 ||
809
0
                    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) {
810
0
                    break; /* invalid attribute */
811
0
                }
812
0
                if (atemplate[i].ulValueLen > 0) {
813
0
                    if (atemplate[i].pValue == NULL ||
814
0
                        atemplate[i].ulValueLen < attr->ulValueLen) {
815
0
                        goto loser;
816
0
                    }
817
0
                } else {
818
0
                    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
819
0
                    if (!atemplate[i].pValue) {
820
0
                        goto loser;
821
0
                    }
822
0
                }
823
0
                nsslibc_memcpy(atemplate[i].pValue,
824
0
                               attr->pValue, attr->ulValueLen);
825
0
                atemplate[i].ulValueLen = attr->ulValueLen;
826
0
                break;
827
0
            }
828
0
        }
829
0
        if (j == cachedOA->numAttributes) {
830
0
            atemplate[i].ulValueLen = (CK_ULONG)-1;
831
0
        }
832
0
    }
833
0
    PR_Unlock(cache->lock);
834
0
    if (mark) {
835
0
        nssArena_Unmark(arena, mark);
836
0
    }
837
0
    return PR_SUCCESS;
838
0
loser:
839
0
    PR_Unlock(cache->lock);
840
0
    if (mark) {
841
0
        nssArena_Release(arena, mark);
842
0
    }
843
0
    return PR_FAILURE;
844
0
}
845
846
NSS_IMPLEMENT PRStatus
847
nssTokenObjectCache_ImportObject(
848
    nssTokenObjectCache *cache,
849
    nssCryptokiObject *object,
850
    CK_OBJECT_CLASS objclass,
851
    CK_ATTRIBUTE_PTR ot,
852
    CK_ULONG otlen)
853
0
{
854
0
    PRStatus status = PR_SUCCESS;
855
0
    PRUint32 count;
856
0
    nssCryptokiObjectAndAttributes **oa, ***otype;
857
0
    PRUint32 objectType;
858
0
    PRBool haveIt = PR_FALSE;
859
860
0
    if (!token_is_present(cache)) {
861
0
        return PR_SUCCESS; /* cache not active, ignored */
862
0
    }
863
0
    PR_Lock(cache->lock);
864
0
    switch (objclass) {
865
0
        case CKO_CERTIFICATE:
866
0
            objectType = cachedCerts;
867
0
            break;
868
0
        case CKO_NSS_TRUST:
869
0
        case CKO_TRUST:
870
0
            objectType = cachedTrust;
871
0
            object->trustType = objclass;
872
0
            break;
873
0
        case CKO_NSS_CRL:
874
0
            objectType = cachedCRLs;
875
0
            break;
876
0
        default:
877
0
            PR_Unlock(cache->lock);
878
0
            return PR_SUCCESS; /* don't need to import it here */
879
0
    }
880
0
    if (!cache_available_for_object_type(cache, objectType)) {
881
0
        PR_Unlock(cache->lock);
882
0
        return PR_SUCCESS; /* cache not active, ignored */
883
0
    }
884
0
    count = 0;
885
0
    otype = &cache->objects[objectType]; /* index into array of types */
886
0
    oa = *otype;                         /* the array of objects for this type */
887
0
    while (oa && *oa) {
888
0
        if (nssCryptokiObject_Equal((*oa)->object, object)) {
889
0
            haveIt = PR_TRUE;
890
0
            break;
891
0
        }
892
0
        count++;
893
0
        oa++;
894
0
    }
895
0
    if (haveIt) {
896
        /* Destroy the old entry */
897
0
        (*oa)->object->token = NULL;
898
0
        nssCryptokiObject_Destroy((*oa)->object);
899
0
        nssArena_Destroy((*oa)->arena);
900
0
    } else {
901
        /* Create space for a new entry */
902
0
        if (count > 0) {
903
0
            *otype = nss_ZREALLOCARRAY(*otype,
904
0
                                       nssCryptokiObjectAndAttributes *,
905
0
                                       count + 2);
906
0
        } else {
907
0
            *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
908
0
        }
909
0
    }
910
0
    if (*otype) {
911
0
        nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
912
0
        (*otype)[count] = create_object_of_type(copyObject, objectType,
913
0
                                                &status);
914
0
    } else {
915
0
        status = PR_FAILURE;
916
0
    }
917
0
    PR_Unlock(cache->lock);
918
0
    return status;
919
0
}
920
921
NSS_IMPLEMENT void
922
nssTokenObjectCache_RemoveObject(
923
    nssTokenObjectCache *cache,
924
    nssCryptokiObject *object)
925
0
{
926
0
    PRUint32 oType;
927
0
    nssCryptokiObjectAndAttributes **oa, **swp = NULL;
928
0
    if (!token_is_present(cache)) {
929
0
        return;
930
0
    }
931
0
    PR_Lock(cache->lock);
932
0
    for (oType = 0; oType < 3; oType++) {
933
0
        if (!cache_available_for_object_type(cache, oType) ||
934
0
            !cache->objects[oType]) {
935
0
            continue;
936
0
        }
937
0
        for (oa = cache->objects[oType]; *oa; oa++) {
938
0
            if (nssCryptokiObject_Equal((*oa)->object, object)) {
939
0
                swp = oa; /* the entry to remove */
940
0
                while (oa[1])
941
0
                    oa++; /* go to the tail */
942
0
                (*swp)->object->token = NULL;
943
0
                nssCryptokiObject_Destroy((*swp)->object);
944
0
                nssArena_Destroy((*swp)->arena); /* destroy it */
945
0
                *swp = *oa;                      /* swap the last with the removed */
946
0
                *oa = NULL;                      /* null-terminate the array */
947
0
                break;
948
0
            }
949
0
        }
950
0
        if (swp) {
951
0
            break;
952
0
        }
953
0
    }
954
0
    if ((oType < 3) &&
955
0
        cache->objects[oType] && cache->objects[oType][0] == NULL) {
956
0
        nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
957
0
        cache->objects[oType] = NULL;
958
0
    }
959
0
    PR_Unlock(cache->lock);
960
0
}
961
962
/* We need a general hash to support CKO_TRUST
963
** Replace the algorithm specific version used for
964
** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
965
** CKA_HASH_OF_CERTIFICATE uses the mechanism specified
966
** in CKA_NAME_HASH_ALGORITHM, with can be passed to this
967
** function.
968
*/
969
/* XXX of course this doesn't belong here */
970
NSS_IMPLEMENT NSSAlgorithmAndParameters *
971
NSSAlgorithmAndParameters_CreateDigest(
972
    NSSArena *arenaOpt, CK_MECHANISM_TYPE hashMech)
973
0
{
974
0
    NSSAlgorithmAndParameters *rvAP = NULL;
975
0
    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
976
0
    if (rvAP) {
977
0
        rvAP->mechanism.mechanism = hashMech;
978
0
        rvAP->mechanism.pParameter = NULL;
979
0
        rvAP->mechanism.ulParameterLen = 0;
980
0
    }
981
0
    return rvAP;
982
0
}
983
984
/*
985
 * we need a DigestBuf for both create and verify trust objects.
986
 * So put it here for now. We don't have any Stan based crypto operations
987
 * yet.
988
 */
989
NSS_IMPLEMENT PRStatus
990
NSSAlgorithm_DigestBuf(CK_MECHANISM_TYPE type, NSSItem *input, NSSItem *output)
991
0
{
992
0
    PRStatus ret = PR_FAILURE;
993
0
    NSSAlgorithmAndParameters *ap = NULL;
994
0
    PK11SlotInfo *internal = NULL;
995
0
    NSSToken *token = NULL;
996
0
    NSSItem *dummy = NULL;
997
998
0
    internal = PK11_GetInternalSlot();
999
0
    if (!internal) {
1000
0
        goto done;
1001
0
    }
1002
0
    token = PK11Slot_GetNSSToken(internal);
1003
0
    if (!token) {
1004
0
        goto done;
1005
0
    }
1006
0
    ap = NSSAlgorithmAndParameters_CreateDigest(NULL, type);
1007
0
    if (!token) {
1008
0
        goto done;
1009
0
    }
1010
1011
0
    dummy = nssToken_Digest(token, NULL, ap, input, output, NULL);
1012
0
    if (dummy) {
1013
0
        ret = PR_SUCCESS;
1014
0
    }
1015
1016
0
done:
1017
0
    nss_ZFreeIf(ap);
1018
0
    if (token) {
1019
0
        (void)nssToken_Destroy(token);
1020
0
    }
1021
0
    if (internal) {
1022
0
        PK11_FreeSlot(internal);
1023
0
    }
1024
0
    return ret;
1025
0
}