Coverage Report

Created: 2026-06-07 07:11

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