Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/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
0
{
130
0
    if (slots) {
131
0
        NSSSlot **slotp;
132
0
        for (slotp = slots; *slotp; slotp++) {
133
0
            nssSlot_Destroy(*slotp);
134
0
        }
135
0
        nss_ZFreeIf(slots);
136
0
    }
137
0
}
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
0
{
260
0
    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
0
}
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
    object->token = NULL;
363
0
    rvCachedObject->object = object;
364
0
    rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
365
0
    if (!rvCachedObject->attributes) {
366
0
        goto loser;
367
0
    }
368
0
    for (j = 0; j < numTypes; j++) {
369
0
        rvCachedObject->attributes[j].type = types[j];
370
0
    }
371
0
    *status = nssCKObject_GetAttributes(object->handle,
372
0
                                        rvCachedObject->attributes,
373
0
                                        numTypes,
374
0
                                        arena,
375
0
                                        session,
376
0
                                        slot);
377
0
    if (*status != PR_SUCCESS) {
378
0
        goto loser;
379
0
    }
380
0
    rvCachedObject->numAttributes = numTypes;
381
0
    *status = PR_SUCCESS;
382
0
    nssSlot_Destroy(slot);
383
384
0
    return rvCachedObject;
385
0
loser:
386
0
    *status = PR_FAILURE;
387
0
    if (slot) {
388
0
        nssSlot_Destroy(slot);
389
0
    }
390
0
    if (arena)
391
0
        nssArena_Destroy(arena);
392
0
    return (nssCryptokiObjectAndAttributes *)NULL;
393
0
}
394
395
/*
396
 *
397
 * State diagram for cache:
398
 *
399
 *            token !present            token removed
400
 *        +-------------------------+<----------------------+
401
 *        |                         ^                       |
402
 *        v                         |                       |
403
 *  +----------+   slot friendly    |  token present   +----------+
404
 *  |   cache  | -----------------> % ---------------> |   cache  |
405
 *  | unloaded |                                       |  loaded  |
406
 *  +----------+                                       +----------+
407
 *    ^   |                                                 ^   |
408
 *    |   |   slot !friendly           slot logged in       |   |
409
 *    |   +-----------------------> % ----------------------+   |
410
 *    |                             |                           |
411
 *    | slot logged out             v  slot !friendly           |
412
 *    +-----------------------------+<--------------------------+
413
 *
414
 */
415
416
/* This function must not be called with cache->lock locked. */
417
static PRBool
418
token_is_present(
419
    nssTokenObjectCache *cache)
420
0
{
421
0
    NSSSlot *slot = nssToken_GetSlot(cache->token);
422
0
    PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
423
0
    nssSlot_Destroy(slot);
424
0
    return tokenPresent;
425
0
}
426
427
static PRBool
428
search_for_objects(
429
    nssTokenObjectCache *cache)
430
0
{
431
0
    PRBool doSearch = PR_FALSE;
432
0
    NSSSlot *slot = nssToken_GetSlot(cache->token);
433
    /* Handle non-friendly slots (slots which require login for objects) */
434
0
    if (!nssSlot_IsFriendly(slot)) {
435
0
        if (nssSlot_IsLoggedIn(slot)) {
436
            /* Either no state change, or went from !logged in -> logged in */
437
0
            cache->loggedIn = PR_TRUE;
438
0
            doSearch = PR_TRUE;
439
0
        } else {
440
0
            if (cache->loggedIn) {
441
                /* went from logged in -> !logged in, destroy cached objects */
442
0
                clear_cache(cache);
443
0
                cache->loggedIn = PR_FALSE;
444
0
            } /* else no state change, still not logged in, so exit */
445
0
        }
446
0
    } else {
447
        /* slot is friendly, thus always available for search */
448
0
        doSearch = PR_TRUE;
449
0
    }
450
0
    nssSlot_Destroy(slot);
451
0
    return doSearch;
452
0
}
453
454
static nssCryptokiObjectAndAttributes *
455
create_cert(
456
    nssCryptokiObject *object,
457
    PRStatus *status)
458
0
{
459
0
    static const CK_ATTRIBUTE_TYPE certAttr[] = {
460
0
        CKA_CLASS,
461
0
        CKA_TOKEN,
462
0
        CKA_LABEL,
463
0
        CKA_CERTIFICATE_TYPE,
464
0
        CKA_ID,
465
0
        CKA_VALUE,
466
0
        CKA_ISSUER,
467
0
        CKA_SERIAL_NUMBER,
468
0
        CKA_SUBJECT,
469
0
        CKA_NSS_EMAIL
470
0
    };
471
0
    static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
472
0
    return create_object(object, certAttr, numCertAttr, status);
473
0
}
474
475
static nssCryptokiObjectAndAttributes *
476
create_trust(
477
    nssCryptokiObject *object,
478
    PRStatus *status)
479
0
{
480
0
    static const CK_ATTRIBUTE_TYPE trustAttr[] = {
481
0
        CKA_CLASS,
482
0
        CKA_TOKEN,
483
0
        CKA_LABEL,
484
0
        CKA_CERT_SHA1_HASH,
485
0
        CKA_CERT_MD5_HASH,
486
0
        CKA_ISSUER,
487
0
        CKA_SUBJECT,
488
0
        CKA_TRUST_SERVER_AUTH,
489
0
        CKA_TRUST_CLIENT_AUTH,
490
0
        CKA_TRUST_EMAIL_PROTECTION,
491
0
        CKA_TRUST_CODE_SIGNING
492
0
    };
493
0
    static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
494
0
    return create_object(object, trustAttr, numTrustAttr, status);
495
0
}
496
497
static nssCryptokiObjectAndAttributes *
498
create_crl(
499
    nssCryptokiObject *object,
500
    PRStatus *status)
501
0
{
502
0
    static const CK_ATTRIBUTE_TYPE crlAttr[] = {
503
0
        CKA_CLASS,
504
0
        CKA_TOKEN,
505
0
        CKA_LABEL,
506
0
        CKA_VALUE,
507
0
        CKA_SUBJECT,
508
0
        CKA_NSS_KRL,
509
0
        CKA_NSS_URL
510
0
    };
511
0
    static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
512
0
    return create_object(object, crlAttr, numCRLAttr, status);
513
0
}
514
515
/* Dispatch to the create function for the object type */
516
static nssCryptokiObjectAndAttributes *
517
create_object_of_type(
518
    nssCryptokiObject *object,
519
    PRUint32 objectType,
520
    PRStatus *status)
521
0
{
522
0
    if (objectType == cachedCerts) {
523
0
        return create_cert(object, status);
524
0
    }
525
0
    if (objectType == cachedTrust) {
526
0
        return create_trust(object, status);
527
0
    }
528
0
    if (objectType == cachedCRLs) {
529
0
        return create_crl(object, status);
530
0
    }
531
0
    return (nssCryptokiObjectAndAttributes *)NULL;
532
0
}
533
534
static PRStatus
535
get_token_objects_for_cache(
536
    nssTokenObjectCache *cache,
537
    PRUint32 objectType,
538
    CK_OBJECT_CLASS objclass)
539
0
{
540
0
    PRStatus status;
541
0
    nssCryptokiObject **objects;
542
0
    PRBool *doIt = &cache->doObjectType[objectType];
543
0
    PRUint32 i, numObjects;
544
545
0
    if (!search_for_objects(cache) ||
546
0
        cache->searchedObjectType[objectType] ||
547
0
        !cache->doObjectType[objectType]) {
548
        /* Either there was a state change that prevents a search
549
         * (token logged out), or the search was already done,
550
         * or objects of this type are not being cached.
551
         */
552
0
        return PR_SUCCESS;
553
0
    }
554
0
    objects = nssToken_FindObjects(cache->token, NULL, objclass,
555
0
                                   nssTokenSearchType_TokenForced,
556
0
                                   MAX_LOCAL_CACHE_OBJECTS, &status);
557
0
    if (status != PR_SUCCESS) {
558
0
        return status;
559
0
    }
560
0
    cache->objects[objectType] = create_object_array(objects,
561
0
                                                     doIt,
562
0
                                                     &numObjects,
563
0
                                                     &status);
564
0
    if (status != PR_SUCCESS) {
565
0
        nssCryptokiObjectArray_Destroy(objects);
566
0
        return status;
567
0
    }
568
0
    for (i = 0; i < numObjects; i++) {
569
0
        cache->objects[objectType][i] = create_object_of_type(objects[i],
570
0
                                                              objectType,
571
0
                                                              &status);
572
0
        if (status != PR_SUCCESS) {
573
0
            break;
574
0
        }
575
0
    }
576
0
    if (status == PR_SUCCESS) {
577
0
        nss_ZFreeIf(objects);
578
0
    } else {
579
0
        PRUint32 j;
580
0
        for (j = 0; j < i; j++) {
581
            /* create_object() allocates an arena into
582
             * cache->objects[objectType][j]->arena on success.
583
             */
584
0
            nssArena_Destroy(cache->objects[objectType][j]->arena);
585
0
        }
586
0
        nss_ZFreeIf(cache->objects[objectType]);
587
0
        cache->objects[objectType] = NULL;
588
0
        nssCryptokiObjectArray_Destroy(objects);
589
0
    }
590
0
    cache->searchedObjectType[objectType] = PR_TRUE;
591
0
    return status;
592
0
}
593
594
static CK_ATTRIBUTE_PTR
595
find_attribute_in_object(
596
    nssCryptokiObjectAndAttributes *obj,
597
    CK_ATTRIBUTE_TYPE attrType)
598
0
{
599
0
    PRUint32 j;
600
0
    for (j = 0; j < obj->numAttributes; j++) {
601
0
        if (attrType == obj->attributes[j].type) {
602
0
            return &obj->attributes[j];
603
0
        }
604
0
    }
605
0
    return (CK_ATTRIBUTE_PTR)NULL;
606
0
}
607
608
/* Find all objects in the array that match the supplied template */
609
static nssCryptokiObject **
610
find_objects_in_array(
611
    nssCryptokiObjectAndAttributes **objArray,
612
    CK_ATTRIBUTE_PTR ot,
613
    CK_ULONG otlen,
614
    PRUint32 maximumOpt)
615
0
{
616
0
    PRIntn oi = 0;
617
0
    PRUint32 i;
618
0
    NSSArena *arena;
619
0
    PRUint32 size = 8;
620
0
    PRUint32 numMatches = 0;
621
0
    nssCryptokiObject **objects = NULL;
622
0
    nssCryptokiObjectAndAttributes **matches = NULL;
623
0
    CK_ATTRIBUTE_PTR attr;
624
625
0
    if (!objArray) {
626
0
        return (nssCryptokiObject **)NULL;
627
0
    }
628
0
    arena = nssArena_Create();
629
0
    if (!arena) {
630
0
        return (nssCryptokiObject **)NULL;
631
0
    }
632
0
    matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
633
0
    if (!matches) {
634
0
        goto loser;
635
0
    }
636
0
    if (maximumOpt == 0)
637
0
        maximumOpt = ~0;
638
    /* loop over the cached objects */
639
0
    for (; *objArray && numMatches < maximumOpt; objArray++) {
640
0
        nssCryptokiObjectAndAttributes *obj = *objArray;
641
        /* loop over the test template */
642
0
        for (i = 0; i < otlen; i++) {
643
            /* see if the object has the attribute */
644
0
            attr = find_attribute_in_object(obj, ot[i].type);
645
0
            if (!attr) {
646
                /* nope, match failed */
647
0
                break;
648
0
            }
649
            /* compare the attribute against the test value */
650
0
            if (ot[i].ulValueLen != attr->ulValueLen ||
651
0
                !nsslibc_memequal(ot[i].pValue,
652
0
                                  attr->pValue,
653
0
                                  attr->ulValueLen, NULL)) {
654
                /* nope, match failed */
655
0
                break;
656
0
            }
657
0
        }
658
0
        if (i == otlen) {
659
            /* all of the attributes in the test template were found
660
             * in the object's template, and they all matched
661
             */
662
0
            matches[numMatches++] = obj;
663
0
            if (numMatches == size) {
664
0
                size *= 2;
665
0
                matches = nss_ZREALLOCARRAY(matches,
666
0
                                            nssCryptokiObjectAndAttributes *,
667
0
                                            size);
668
0
                if (!matches) {
669
0
                    goto loser;
670
0
                }
671
0
            }
672
0
        }
673
0
    }
674
0
    if (numMatches > 0) {
675
0
        objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
676
0
        if (!objects) {
677
0
            goto loser;
678
0
        }
679
0
        for (oi = 0; oi < (PRIntn)numMatches; oi++) {
680
0
            objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
681
0
            if (!objects[oi]) {
682
0
                goto loser;
683
0
            }
684
0
        }
685
0
    }
686
0
    nssArena_Destroy(arena);
687
0
    return objects;
688
0
loser:
689
0
    nssCryptokiObjectArray_Destroy(objects);
690
0
    nssArena_Destroy(arena);
691
0
    return (nssCryptokiObject **)NULL;
692
0
}
693
694
NSS_IMPLEMENT nssCryptokiObject **
695
nssTokenObjectCache_FindObjectsByTemplate(
696
    nssTokenObjectCache *cache,
697
    CK_OBJECT_CLASS objclass,
698
    CK_ATTRIBUTE_PTR otemplate,
699
    CK_ULONG otlen,
700
    PRUint32 maximumOpt,
701
    PRStatus *statusOpt)
702
0
{
703
0
    PRStatus status = PR_FAILURE;
704
0
    nssCryptokiObject **rvObjects = NULL;
705
0
    PRUint32 objectType;
706
0
    if (!token_is_present(cache)) {
707
0
        status = PR_SUCCESS;
708
0
        goto finish;
709
0
    }
710
0
    switch (objclass) {
711
0
        case CKO_CERTIFICATE:
712
0
            objectType = cachedCerts;
713
0
            break;
714
0
        case CKO_NSS_TRUST:
715
0
            objectType = cachedTrust;
716
0
            break;
717
0
        case CKO_NSS_CRL:
718
0
            objectType = cachedCRLs;
719
0
            break;
720
0
        default:
721
0
            goto finish;
722
0
    }
723
0
    PZ_Lock(cache->lock);
724
0
    if (cache->doObjectType[objectType]) {
725
0
        status = get_token_objects_for_cache(cache, objectType, objclass);
726
0
        if (status == PR_SUCCESS) {
727
0
            rvObjects = find_objects_in_array(cache->objects[objectType],
728
0
                                              otemplate, otlen, maximumOpt);
729
0
        }
730
0
    }
731
0
    PZ_Unlock(cache->lock);
732
0
finish:
733
0
    if (statusOpt) {
734
0
        *statusOpt = status;
735
0
    }
736
0
    return rvObjects;
737
0
}
738
739
static PRBool
740
cache_available_for_object_type(
741
    nssTokenObjectCache *cache,
742
    PRUint32 objectType)
743
0
{
744
0
    if (!cache->doObjectType[objectType]) {
745
        /* not caching this object kind */
746
0
        return PR_FALSE;
747
0
    }
748
0
    if (!cache->searchedObjectType[objectType]) {
749
        /* objects are not cached yet */
750
0
        return PR_FALSE;
751
0
    }
752
0
    if (!search_for_objects(cache)) {
753
        /* not logged in */
754
0
        return PR_FALSE;
755
0
    }
756
0
    return PR_TRUE;
757
0
}
758
759
NSS_IMPLEMENT PRStatus
760
nssTokenObjectCache_GetObjectAttributes(
761
    nssTokenObjectCache *cache,
762
    NSSArena *arenaOpt,
763
    nssCryptokiObject *object,
764
    CK_OBJECT_CLASS objclass,
765
    CK_ATTRIBUTE_PTR atemplate,
766
    CK_ULONG atlen)
767
0
{
768
0
    PRUint32 i, j;
769
0
    NSSArena *arena = NULL;
770
0
    nssArenaMark *mark = NULL;
771
0
    nssCryptokiObjectAndAttributes *cachedOA = NULL;
772
0
    nssCryptokiObjectAndAttributes **oa = NULL;
773
0
    PRUint32 objectType;
774
0
    if (!token_is_present(cache)) {
775
0
        return PR_FAILURE;
776
0
    }
777
0
    PZ_Lock(cache->lock);
778
0
    switch (objclass) {
779
0
        case CKO_CERTIFICATE:
780
0
            objectType = cachedCerts;
781
0
            break;
782
0
        case CKO_NSS_TRUST:
783
0
            objectType = cachedTrust;
784
0
            break;
785
0
        case CKO_NSS_CRL:
786
0
            objectType = cachedCRLs;
787
0
            break;
788
0
        default:
789
0
            goto loser;
790
0
    }
791
0
    if (!cache_available_for_object_type(cache, objectType)) {
792
0
        goto loser;
793
0
    }
794
0
    oa = cache->objects[objectType];
795
0
    if (!oa) {
796
0
        goto loser;
797
0
    }
798
0
    for (; *oa; oa++) {
799
0
        if (nssCryptokiObject_Equal((*oa)->object, object)) {
800
0
            cachedOA = *oa;
801
0
            break;
802
0
        }
803
0
    }
804
0
    if (!cachedOA) {
805
0
        goto loser; /* don't have this object */
806
0
    }
807
0
    if (arenaOpt) {
808
0
        arena = arenaOpt;
809
0
        mark = nssArena_Mark(arena);
810
0
    }
811
0
    for (i = 0; i < atlen; i++) {
812
0
        for (j = 0; j < cachedOA->numAttributes; j++) {
813
0
            if (atemplate[i].type == cachedOA->attributes[j].type) {
814
0
                CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
815
0
                if (cachedOA->attributes[j].ulValueLen == 0 ||
816
0
                    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) {
817
0
                    break; /* invalid attribute */
818
0
                }
819
0
                if (atemplate[i].ulValueLen > 0) {
820
0
                    if (atemplate[i].pValue == NULL ||
821
0
                        atemplate[i].ulValueLen < attr->ulValueLen) {
822
0
                        goto loser;
823
0
                    }
824
0
                } else {
825
0
                    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
826
0
                    if (!atemplate[i].pValue) {
827
0
                        goto loser;
828
0
                    }
829
0
                }
830
0
                nsslibc_memcpy(atemplate[i].pValue,
831
0
                               attr->pValue, attr->ulValueLen);
832
0
                atemplate[i].ulValueLen = attr->ulValueLen;
833
0
                break;
834
0
            }
835
0
        }
836
0
        if (j == cachedOA->numAttributes) {
837
0
            atemplate[i].ulValueLen = (CK_ULONG)-1;
838
0
        }
839
0
    }
840
0
    PZ_Unlock(cache->lock);
841
0
    if (mark) {
842
0
        nssArena_Unmark(arena, mark);
843
0
    }
844
0
    return PR_SUCCESS;
845
0
loser:
846
0
    PZ_Unlock(cache->lock);
847
0
    if (mark) {
848
0
        nssArena_Release(arena, mark);
849
0
    }
850
0
    return PR_FAILURE;
851
0
}
852
853
NSS_IMPLEMENT PRStatus
854
nssTokenObjectCache_ImportObject(
855
    nssTokenObjectCache *cache,
856
    nssCryptokiObject *object,
857
    CK_OBJECT_CLASS objclass,
858
    CK_ATTRIBUTE_PTR ot,
859
    CK_ULONG otlen)
860
0
{
861
0
    PRStatus status = PR_SUCCESS;
862
0
    PRUint32 count;
863
0
    nssCryptokiObjectAndAttributes **oa, ***otype;
864
0
    PRUint32 objectType;
865
0
    PRBool haveIt = PR_FALSE;
866
867
0
    if (!token_is_present(cache)) {
868
0
        return PR_SUCCESS; /* cache not active, ignored */
869
0
    }
870
0
    PZ_Lock(cache->lock);
871
0
    switch (objclass) {
872
0
        case CKO_CERTIFICATE:
873
0
            objectType = cachedCerts;
874
0
            break;
875
0
        case CKO_NSS_TRUST:
876
0
            objectType = cachedTrust;
877
0
            break;
878
0
        case CKO_NSS_CRL:
879
0
            objectType = cachedCRLs;
880
0
            break;
881
0
        default:
882
0
            PZ_Unlock(cache->lock);
883
0
            return PR_SUCCESS; /* don't need to import it here */
884
0
    }
885
0
    if (!cache_available_for_object_type(cache, objectType)) {
886
0
        PZ_Unlock(cache->lock);
887
0
        return PR_SUCCESS; /* cache not active, ignored */
888
0
    }
889
0
    count = 0;
890
0
    otype = &cache->objects[objectType]; /* index into array of types */
891
0
    oa = *otype;                         /* the array of objects for this type */
892
0
    while (oa && *oa) {
893
0
        if (nssCryptokiObject_Equal((*oa)->object, object)) {
894
0
            haveIt = PR_TRUE;
895
0
            break;
896
0
        }
897
0
        count++;
898
0
        oa++;
899
0
    }
900
0
    if (haveIt) {
901
        /* Destroy the old entry */
902
0
        (*oa)->object->token = NULL;
903
0
        nssCryptokiObject_Destroy((*oa)->object);
904
0
        nssArena_Destroy((*oa)->arena);
905
0
    } else {
906
        /* Create space for a new entry */
907
0
        if (count > 0) {
908
0
            *otype = nss_ZREALLOCARRAY(*otype,
909
0
                                       nssCryptokiObjectAndAttributes *,
910
0
                                       count + 2);
911
0
        } else {
912
0
            *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
913
0
        }
914
0
    }
915
0
    if (*otype) {
916
0
        nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
917
0
        (*otype)[count] = create_object_of_type(copyObject, objectType,
918
0
                                                &status);
919
0
    } else {
920
0
        status = PR_FAILURE;
921
0
    }
922
0
    PZ_Unlock(cache->lock);
923
0
    return status;
924
0
}
925
926
NSS_IMPLEMENT void
927
nssTokenObjectCache_RemoveObject(
928
    nssTokenObjectCache *cache,
929
    nssCryptokiObject *object)
930
0
{
931
0
    PRUint32 oType;
932
0
    nssCryptokiObjectAndAttributes **oa, **swp = NULL;
933
0
    if (!token_is_present(cache)) {
934
0
        return;
935
0
    }
936
0
    PZ_Lock(cache->lock);
937
0
    for (oType = 0; oType < 3; oType++) {
938
0
        if (!cache_available_for_object_type(cache, oType) ||
939
0
            !cache->objects[oType]) {
940
0
            continue;
941
0
        }
942
0
        for (oa = cache->objects[oType]; *oa; oa++) {
943
0
            if (nssCryptokiObject_Equal((*oa)->object, object)) {
944
0
                swp = oa; /* the entry to remove */
945
0
                while (oa[1])
946
0
                    oa++; /* go to the tail */
947
0
                (*swp)->object->token = NULL;
948
0
                nssCryptokiObject_Destroy((*swp)->object);
949
0
                nssArena_Destroy((*swp)->arena); /* destroy it */
950
0
                *swp = *oa;                      /* swap the last with the removed */
951
0
                *oa = NULL;                      /* null-terminate the array */
952
0
                break;
953
0
            }
954
0
        }
955
0
        if (swp) {
956
0
            break;
957
0
        }
958
0
    }
959
0
    if ((oType < 3) &&
960
0
        cache->objects[oType] && cache->objects[oType][0] == NULL) {
961
0
        nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
962
0
        cache->objects[oType] = NULL;
963
0
    }
964
0
    PZ_Unlock(cache->lock);
965
0
}
966
967
/* These two hash algorithms are presently sufficient.
968
** They are used for fingerprints of certs which are stored as the
969
** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
970
** We don't need to add SHAxxx to these now.
971
*/
972
/* XXX of course this doesn't belong here */
973
NSS_IMPLEMENT NSSAlgorithmAndParameters *
974
NSSAlgorithmAndParameters_CreateSHA1Digest(
975
    NSSArena *arenaOpt)
976
0
{
977
0
    NSSAlgorithmAndParameters *rvAP = NULL;
978
0
    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
979
0
    if (rvAP) {
980
0
        rvAP->mechanism.mechanism = CKM_SHA_1;
981
0
        rvAP->mechanism.pParameter = NULL;
982
0
        rvAP->mechanism.ulParameterLen = 0;
983
0
    }
984
0
    return rvAP;
985
0
}
986
987
NSS_IMPLEMENT NSSAlgorithmAndParameters *
988
NSSAlgorithmAndParameters_CreateMD5Digest(
989
    NSSArena *arenaOpt)
990
0
{
991
0
    NSSAlgorithmAndParameters *rvAP = NULL;
992
0
    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
993
0
    if (rvAP) {
994
0
        rvAP->mechanism.mechanism = CKM_MD5;
995
0
        rvAP->mechanism.pParameter = NULL;
996
0
        rvAP->mechanism.ulParameterLen = 0;
997
0
    }
998
0
    return rvAP;
999
0
}