Coverage Report

Created: 2026-04-04 06:13

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