Coverage Report

Created: 2025-07-04 06:19

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