Coverage Report

Created: 2018-09-25 14:53

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