Coverage Report

Created: 2024-05-20 06:23

/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
17.7k
{
130
17.7k
    if (slots) {
131
17.7k
        NSSSlot **slotp;
132
53.2k
        for (slotp = slots; *slotp; slotp++) {
133
35.4k
            nssSlot_Destroy(*slotp);
134
35.4k
        }
135
17.7k
        nss_ZFreeIf(slots);
136
17.7k
    }
137
17.7k
}
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
17.5k
{
260
17.5k
    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
17.5k
}
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
            /* Any token references that were removed in successful loop iterations
581
             * need to be restored before we call nssCryptokiObjectArray_Destroy */
582
0
            nssToken_AddRef(cache->objects[objectType][j]->object->token);
583
0
            nssArena_Destroy(cache->objects[objectType][j]->arena);
584
0
        }
585
0
        nss_ZFreeIf(cache->objects[objectType]);
586
0
        cache->objects[objectType] = NULL;
587
0
        nssCryptokiObjectArray_Destroy(objects);
588
0
    }
589
0
    cache->searchedObjectType[objectType] = PR_TRUE;
590
0
    return status;
591
0
}
592
593
static CK_ATTRIBUTE_PTR
594
find_attribute_in_object(
595
    nssCryptokiObjectAndAttributes *obj,
596
    CK_ATTRIBUTE_TYPE attrType)
597
0
{
598
0
    PRUint32 j;
599
0
    for (j = 0; j < obj->numAttributes; j++) {
600
0
        if (attrType == obj->attributes[j].type) {
601
0
            return &obj->attributes[j];
602
0
        }
603
0
    }
604
0
    return (CK_ATTRIBUTE_PTR)NULL;
605
0
}
606
607
/* Find all objects in the array that match the supplied template */
608
static nssCryptokiObject **
609
find_objects_in_array(
610
    nssCryptokiObjectAndAttributes **objArray,
611
    CK_ATTRIBUTE_PTR ot,
612
    CK_ULONG otlen,
613
    PRUint32 maximumOpt)
614
0
{
615
0
    PRIntn oi = 0;
616
0
    PRUint32 i;
617
0
    NSSArena *arena;
618
0
    PRUint32 size = 8;
619
0
    PRUint32 numMatches = 0;
620
0
    nssCryptokiObject **objects = NULL;
621
0
    nssCryptokiObjectAndAttributes **matches = NULL;
622
0
    CK_ATTRIBUTE_PTR attr;
623
624
0
    if (!objArray) {
625
0
        return (nssCryptokiObject **)NULL;
626
0
    }
627
0
    arena = nssArena_Create();
628
0
    if (!arena) {
629
0
        return (nssCryptokiObject **)NULL;
630
0
    }
631
0
    matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
632
0
    if (!matches) {
633
0
        goto loser;
634
0
    }
635
0
    if (maximumOpt == 0)
636
0
        maximumOpt = ~0;
637
    /* loop over the cached objects */
638
0
    for (; *objArray && numMatches < maximumOpt; objArray++) {
639
0
        nssCryptokiObjectAndAttributes *obj = *objArray;
640
        /* loop over the test template */
641
0
        for (i = 0; i < otlen; i++) {
642
            /* see if the object has the attribute */
643
0
            attr = find_attribute_in_object(obj, ot[i].type);
644
0
            if (!attr) {
645
                /* nope, match failed */
646
0
                break;
647
0
            }
648
            /* compare the attribute against the test value */
649
0
            if (ot[i].ulValueLen != attr->ulValueLen ||
650
0
                !nsslibc_memequal(ot[i].pValue,
651
0
                                  attr->pValue,
652
0
                                  attr->ulValueLen, NULL)) {
653
                /* nope, match failed */
654
0
                break;
655
0
            }
656
0
        }
657
0
        if (i == otlen) {
658
            /* all of the attributes in the test template were found
659
             * in the object's template, and they all matched
660
             */
661
0
            matches[numMatches++] = obj;
662
0
            if (numMatches == size) {
663
0
                size *= 2;
664
0
                matches = nss_ZREALLOCARRAY(matches,
665
0
                                            nssCryptokiObjectAndAttributes *,
666
0
                                            size);
667
0
                if (!matches) {
668
0
                    goto loser;
669
0
                }
670
0
            }
671
0
        }
672
0
    }
673
0
    if (numMatches > 0) {
674
0
        objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
675
0
        if (!objects) {
676
0
            goto loser;
677
0
        }
678
0
        for (oi = 0; oi < (PRIntn)numMatches; oi++) {
679
0
            objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
680
0
            if (!objects[oi]) {
681
0
                goto loser;
682
0
            }
683
0
        }
684
0
    }
685
0
    nssArena_Destroy(arena);
686
0
    return objects;
687
0
loser:
688
0
    nssCryptokiObjectArray_Destroy(objects);
689
0
    nssArena_Destroy(arena);
690
0
    return (nssCryptokiObject **)NULL;
691
0
}
692
693
NSS_IMPLEMENT nssCryptokiObject **
694
nssTokenObjectCache_FindObjectsByTemplate(
695
    nssTokenObjectCache *cache,
696
    CK_OBJECT_CLASS objclass,
697
    CK_ATTRIBUTE_PTR otemplate,
698
    CK_ULONG otlen,
699
    PRUint32 maximumOpt,
700
    PRStatus *statusOpt)
701
0
{
702
0
    PRStatus status = PR_FAILURE;
703
0
    nssCryptokiObject **rvObjects = NULL;
704
0
    PRUint32 objectType;
705
0
    if (!token_is_present(cache)) {
706
0
        status = PR_SUCCESS;
707
0
        goto finish;
708
0
    }
709
0
    switch (objclass) {
710
0
        case CKO_CERTIFICATE:
711
0
            objectType = cachedCerts;
712
0
            break;
713
0
        case CKO_NSS_TRUST:
714
0
            objectType = cachedTrust;
715
0
            break;
716
0
        case CKO_NSS_CRL:
717
0
            objectType = cachedCRLs;
718
0
            break;
719
0
        default:
720
0
            goto finish;
721
0
    }
722
0
    PZ_Lock(cache->lock);
723
0
    if (cache->doObjectType[objectType]) {
724
0
        status = get_token_objects_for_cache(cache, objectType, objclass);
725
0
        if (status == PR_SUCCESS) {
726
0
            rvObjects = find_objects_in_array(cache->objects[objectType],
727
0
                                              otemplate, otlen, maximumOpt);
728
0
        }
729
0
    }
730
0
    PZ_Unlock(cache->lock);
731
0
finish:
732
0
    if (statusOpt) {
733
0
        *statusOpt = status;
734
0
    }
735
0
    return rvObjects;
736
0
}
737
738
static PRBool
739
cache_available_for_object_type(
740
    nssTokenObjectCache *cache,
741
    PRUint32 objectType)
742
0
{
743
0
    if (!cache->doObjectType[objectType]) {
744
        /* not caching this object kind */
745
0
        return PR_FALSE;
746
0
    }
747
0
    if (!cache->searchedObjectType[objectType]) {
748
        /* objects are not cached yet */
749
0
        return PR_FALSE;
750
0
    }
751
0
    if (!search_for_objects(cache)) {
752
        /* not logged in */
753
0
        return PR_FALSE;
754
0
    }
755
0
    return PR_TRUE;
756
0
}
757
758
NSS_IMPLEMENT PRStatus
759
nssTokenObjectCache_GetObjectAttributes(
760
    nssTokenObjectCache *cache,
761
    NSSArena *arenaOpt,
762
    nssCryptokiObject *object,
763
    CK_OBJECT_CLASS objclass,
764
    CK_ATTRIBUTE_PTR atemplate,
765
    CK_ULONG atlen)
766
0
{
767
0
    PRUint32 i, j;
768
0
    NSSArena *arena = NULL;
769
0
    nssArenaMark *mark = NULL;
770
0
    nssCryptokiObjectAndAttributes *cachedOA = NULL;
771
0
    nssCryptokiObjectAndAttributes **oa = NULL;
772
0
    PRUint32 objectType;
773
0
    if (!token_is_present(cache)) {
774
0
        return PR_FAILURE;
775
0
    }
776
0
    PZ_Lock(cache->lock);
777
0
    switch (objclass) {
778
0
        case CKO_CERTIFICATE:
779
0
            objectType = cachedCerts;
780
0
            break;
781
0
        case CKO_NSS_TRUST:
782
0
            objectType = cachedTrust;
783
0
            break;
784
0
        case CKO_NSS_CRL:
785
0
            objectType = cachedCRLs;
786
0
            break;
787
0
        default:
788
0
            goto loser;
789
0
    }
790
0
    if (!cache_available_for_object_type(cache, objectType)) {
791
0
        goto loser;
792
0
    }
793
0
    oa = cache->objects[objectType];
794
0
    if (!oa) {
795
0
        goto loser;
796
0
    }
797
0
    for (; *oa; oa++) {
798
0
        if (nssCryptokiObject_Equal((*oa)->object, object)) {
799
0
            cachedOA = *oa;
800
0
            break;
801
0
        }
802
0
    }
803
0
    if (!cachedOA) {
804
0
        goto loser; /* don't have this object */
805
0
    }
806
0
    if (arenaOpt) {
807
0
        arena = arenaOpt;
808
0
        mark = nssArena_Mark(arena);
809
0
    }
810
0
    for (i = 0; i < atlen; i++) {
811
0
        for (j = 0; j < cachedOA->numAttributes; j++) {
812
0
            if (atemplate[i].type == cachedOA->attributes[j].type) {
813
0
                CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
814
0
                if (cachedOA->attributes[j].ulValueLen == 0 ||
815
0
                    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) {
816
0
                    break; /* invalid attribute */
817
0
                }
818
0
                if (atemplate[i].ulValueLen > 0) {
819
0
                    if (atemplate[i].pValue == NULL ||
820
0
                        atemplate[i].ulValueLen < attr->ulValueLen) {
821
0
                        goto loser;
822
0
                    }
823
0
                } else {
824
0
                    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
825
0
                    if (!atemplate[i].pValue) {
826
0
                        goto loser;
827
0
                    }
828
0
                }
829
0
                nsslibc_memcpy(atemplate[i].pValue,
830
0
                               attr->pValue, attr->ulValueLen);
831
0
                atemplate[i].ulValueLen = attr->ulValueLen;
832
0
                break;
833
0
            }
834
0
        }
835
0
        if (j == cachedOA->numAttributes) {
836
0
            atemplate[i].ulValueLen = (CK_ULONG)-1;
837
0
        }
838
0
    }
839
0
    PZ_Unlock(cache->lock);
840
0
    if (mark) {
841
0
        nssArena_Unmark(arena, mark);
842
0
    }
843
0
    return PR_SUCCESS;
844
0
loser:
845
0
    PZ_Unlock(cache->lock);
846
0
    if (mark) {
847
0
        nssArena_Release(arena, mark);
848
0
    }
849
0
    return PR_FAILURE;
850
0
}
851
852
NSS_IMPLEMENT PRStatus
853
nssTokenObjectCache_ImportObject(
854
    nssTokenObjectCache *cache,
855
    nssCryptokiObject *object,
856
    CK_OBJECT_CLASS objclass,
857
    CK_ATTRIBUTE_PTR ot,
858
    CK_ULONG otlen)
859
0
{
860
0
    PRStatus status = PR_SUCCESS;
861
0
    PRUint32 count;
862
0
    nssCryptokiObjectAndAttributes **oa, ***otype;
863
0
    PRUint32 objectType;
864
0
    PRBool haveIt = PR_FALSE;
865
866
0
    if (!token_is_present(cache)) {
867
0
        return PR_SUCCESS; /* cache not active, ignored */
868
0
    }
869
0
    PZ_Lock(cache->lock);
870
0
    switch (objclass) {
871
0
        case CKO_CERTIFICATE:
872
0
            objectType = cachedCerts;
873
0
            break;
874
0
        case CKO_NSS_TRUST:
875
0
            objectType = cachedTrust;
876
0
            break;
877
0
        case CKO_NSS_CRL:
878
0
            objectType = cachedCRLs;
879
0
            break;
880
0
        default:
881
0
            PZ_Unlock(cache->lock);
882
0
            return PR_SUCCESS; /* don't need to import it here */
883
0
    }
884
0
    if (!cache_available_for_object_type(cache, objectType)) {
885
0
        PZ_Unlock(cache->lock);
886
0
        return PR_SUCCESS; /* cache not active, ignored */
887
0
    }
888
0
    count = 0;
889
0
    otype = &cache->objects[objectType]; /* index into array of types */
890
0
    oa = *otype;                         /* the array of objects for this type */
891
0
    while (oa && *oa) {
892
0
        if (nssCryptokiObject_Equal((*oa)->object, object)) {
893
0
            haveIt = PR_TRUE;
894
0
            break;
895
0
        }
896
0
        count++;
897
0
        oa++;
898
0
    }
899
0
    if (haveIt) {
900
        /* Destroy the old entry */
901
0
        (*oa)->object->token = NULL;
902
0
        nssCryptokiObject_Destroy((*oa)->object);
903
0
        nssArena_Destroy((*oa)->arena);
904
0
    } else {
905
        /* Create space for a new entry */
906
0
        if (count > 0) {
907
0
            *otype = nss_ZREALLOCARRAY(*otype,
908
0
                                       nssCryptokiObjectAndAttributes *,
909
0
                                       count + 2);
910
0
        } else {
911
0
            *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
912
0
        }
913
0
    }
914
0
    if (*otype) {
915
0
        nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
916
0
        (*otype)[count] = create_object_of_type(copyObject, objectType,
917
0
                                                &status);
918
0
    } else {
919
0
        status = PR_FAILURE;
920
0
    }
921
0
    PZ_Unlock(cache->lock);
922
0
    return status;
923
0
}
924
925
NSS_IMPLEMENT void
926
nssTokenObjectCache_RemoveObject(
927
    nssTokenObjectCache *cache,
928
    nssCryptokiObject *object)
929
0
{
930
0
    PRUint32 oType;
931
0
    nssCryptokiObjectAndAttributes **oa, **swp = NULL;
932
0
    if (!token_is_present(cache)) {
933
0
        return;
934
0
    }
935
0
    PZ_Lock(cache->lock);
936
0
    for (oType = 0; oType < 3; oType++) {
937
0
        if (!cache_available_for_object_type(cache, oType) ||
938
0
            !cache->objects[oType]) {
939
0
            continue;
940
0
        }
941
0
        for (oa = cache->objects[oType]; *oa; oa++) {
942
0
            if (nssCryptokiObject_Equal((*oa)->object, object)) {
943
0
                swp = oa; /* the entry to remove */
944
0
                while (oa[1])
945
0
                    oa++; /* go to the tail */
946
0
                (*swp)->object->token = NULL;
947
0
                nssCryptokiObject_Destroy((*swp)->object);
948
0
                nssArena_Destroy((*swp)->arena); /* destroy it */
949
0
                *swp = *oa;                      /* swap the last with the removed */
950
0
                *oa = NULL;                      /* null-terminate the array */
951
0
                break;
952
0
            }
953
0
        }
954
0
        if (swp) {
955
0
            break;
956
0
        }
957
0
    }
958
0
    if ((oType < 3) &&
959
0
        cache->objects[oType] && cache->objects[oType][0] == NULL) {
960
0
        nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
961
0
        cache->objects[oType] = NULL;
962
0
    }
963
0
    PZ_Unlock(cache->lock);
964
0
}
965
966
/* These two hash algorithms are presently sufficient.
967
** They are used for fingerprints of certs which are stored as the
968
** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
969
** We don't need to add SHAxxx to these now.
970
*/
971
/* XXX of course this doesn't belong here */
972
NSS_IMPLEMENT NSSAlgorithmAndParameters *
973
NSSAlgorithmAndParameters_CreateSHA1Digest(
974
    NSSArena *arenaOpt)
975
0
{
976
0
    NSSAlgorithmAndParameters *rvAP = NULL;
977
0
    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
978
0
    if (rvAP) {
979
0
        rvAP->mechanism.mechanism = CKM_SHA_1;
980
0
        rvAP->mechanism.pParameter = NULL;
981
0
        rvAP->mechanism.ulParameterLen = 0;
982
0
    }
983
0
    return rvAP;
984
0
}
985
986
NSS_IMPLEMENT NSSAlgorithmAndParameters *
987
NSSAlgorithmAndParameters_CreateMD5Digest(
988
    NSSArena *arenaOpt)
989
0
{
990
0
    NSSAlgorithmAndParameters *rvAP = NULL;
991
0
    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
992
0
    if (rvAP) {
993
0
        rvAP->mechanism.mechanism = CKM_MD5;
994
0
        rvAP->mechanism.pParameter = NULL;
995
0
        rvAP->mechanism.ulParameterLen = 0;
996
0
    }
997
0
    return rvAP;
998
0
}