Coverage Report

Created: 2025-07-01 06:25

/src/nss/lib/pki/pkibase.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 DEV_H
6
#include "dev.h"
7
#endif /* DEV_H */
8
9
#ifndef PKIM_H
10
#include "pkim.h"
11
#endif /* PKIM_H */
12
13
#include "pki3hack.h"
14
15
extern const NSSError NSS_ERROR_NOT_FOUND;
16
17
NSS_IMPLEMENT void
18
nssPKIObject_Lock(nssPKIObject *object)
19
0
{
20
0
    switch (object->lockType) {
21
0
        case nssPKIMonitor:
22
0
            PZ_EnterMonitor(object->sync.mlock);
23
0
            break;
24
0
        case nssPKILock:
25
0
            PZ_Lock(object->sync.lock);
26
0
            break;
27
0
        default:
28
0
            PORT_Assert(0);
29
0
    }
30
0
}
31
32
NSS_IMPLEMENT void
33
nssPKIObject_Unlock(nssPKIObject *object)
34
0
{
35
0
    switch (object->lockType) {
36
0
        case nssPKIMonitor:
37
0
            PZ_ExitMonitor(object->sync.mlock);
38
0
            break;
39
0
        case nssPKILock:
40
0
            PZ_Unlock(object->sync.lock);
41
0
            break;
42
0
        default:
43
0
            PORT_Assert(0);
44
0
    }
45
0
}
46
47
NSS_IMPLEMENT PRStatus
48
nssPKIObject_NewLock(nssPKIObject *object, nssPKILockType lockType)
49
0
{
50
0
    object->lockType = lockType;
51
0
    switch (lockType) {
52
0
        case nssPKIMonitor:
53
0
            object->sync.mlock = PZ_NewMonitor(nssILockSSL);
54
0
            return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
55
0
        case nssPKILock:
56
0
            object->sync.lock = PZ_NewLock(nssILockSSL);
57
0
            return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
58
0
        default:
59
0
            PORT_Assert(0);
60
0
            return PR_FAILURE;
61
0
    }
62
0
}
63
64
NSS_IMPLEMENT void
65
nssPKIObject_DestroyLock(nssPKIObject *object)
66
0
{
67
0
    switch (object->lockType) {
68
0
        case nssPKIMonitor:
69
0
            PZ_DestroyMonitor(object->sync.mlock);
70
0
            object->sync.mlock = NULL;
71
0
            break;
72
0
        case nssPKILock:
73
0
            PZ_DestroyLock(object->sync.lock);
74
0
            object->sync.lock = NULL;
75
0
            break;
76
0
        default:
77
0
            PORT_Assert(0);
78
0
    }
79
0
}
80
81
NSS_IMPLEMENT nssPKIObject *
82
nssPKIObject_Create(
83
    NSSArena *arenaOpt,
84
    nssCryptokiObject *instanceOpt,
85
    NSSTrustDomain *td,
86
    NSSCryptoContext *cc,
87
    nssPKILockType lockType)
88
0
{
89
0
    NSSArena *arena;
90
0
    nssArenaMark *mark = NULL;
91
0
    nssPKIObject *object;
92
0
    if (arenaOpt) {
93
0
        arena = arenaOpt;
94
0
        mark = nssArena_Mark(arena);
95
0
    } else {
96
0
        arena = nssArena_Create();
97
0
        if (!arena) {
98
0
            return (nssPKIObject *)NULL;
99
0
        }
100
0
    }
101
0
    object = nss_ZNEW(arena, nssPKIObject);
102
0
    if (!object) {
103
0
        goto loser;
104
0
    }
105
0
    object->arena = arena;
106
0
    object->trustDomain = td; /* XXX */
107
0
    object->cryptoContext = cc;
108
0
    if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
109
0
        goto loser;
110
0
    }
111
0
    if (instanceOpt) {
112
0
        if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
113
0
            goto loser;
114
0
        }
115
0
    }
116
0
    PR_ATOMIC_INCREMENT(&object->refCount);
117
0
    if (mark) {
118
0
        nssArena_Unmark(arena, mark);
119
0
    }
120
0
    return object;
121
0
loser:
122
0
    if (mark) {
123
0
        nssArena_Release(arena, mark);
124
0
    } else {
125
0
        nssArena_Destroy(arena);
126
0
    }
127
0
    return (nssPKIObject *)NULL;
128
0
}
129
130
NSS_IMPLEMENT PRBool
131
nssPKIObject_Destroy(
132
    nssPKIObject *object)
133
0
{
134
0
    PRUint32 i;
135
0
    PR_ASSERT(object->refCount > 0);
136
0
    if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) {
137
0
        for (i = 0; i < object->numInstances; i++) {
138
0
            nssCryptokiObject_Destroy(object->instances[i]);
139
0
        }
140
0
        nssPKIObject_DestroyLock(object);
141
0
        nssArena_Destroy(object->arena);
142
0
        return PR_TRUE;
143
0
    }
144
0
    return PR_FALSE;
145
0
}
146
147
NSS_IMPLEMENT nssPKIObject *
148
nssPKIObject_AddRef(
149
    nssPKIObject *object)
150
0
{
151
0
    PR_ATOMIC_INCREMENT(&object->refCount);
152
0
    return object;
153
0
}
154
155
NSS_IMPLEMENT PRStatus
156
nssPKIObject_AddInstance(
157
    nssPKIObject *object,
158
    nssCryptokiObject *instance)
159
0
{
160
0
    nssCryptokiObject **newInstances = NULL;
161
162
0
    nssPKIObject_Lock(object);
163
0
    if (object->numInstances == 0) {
164
0
        newInstances = nss_ZNEWARRAY(object->arena,
165
0
                                     nssCryptokiObject *,
166
0
                                     object->numInstances + 1);
167
0
    } else {
168
0
        PRBool found = PR_FALSE;
169
0
        PRUint32 i;
170
0
        for (i = 0; i < object->numInstances; i++) {
171
0
            if (nssCryptokiObject_Equal(object->instances[i], instance)) {
172
0
                found = PR_TRUE;
173
0
                break;
174
0
            }
175
0
        }
176
0
        if (found) {
177
            /* The new instance is identical to one in the array, except
178
             * perhaps that the label may be different.  So replace
179
             * the label in the array instance with the label from the
180
             * new instance, and discard the new instance.
181
             */
182
0
            nss_ZFreeIf(object->instances[i]->label);
183
0
            object->instances[i]->label = instance->label;
184
0
            nssPKIObject_Unlock(object);
185
0
            instance->label = NULL;
186
0
            nssCryptokiObject_Destroy(instance);
187
0
            return PR_SUCCESS;
188
0
        }
189
0
        newInstances = nss_ZREALLOCARRAY(object->instances,
190
0
                                         nssCryptokiObject *,
191
0
                                         object->numInstances + 1);
192
0
    }
193
0
    if (newInstances) {
194
0
        object->instances = newInstances;
195
0
        newInstances[object->numInstances++] = instance;
196
0
    }
197
0
    nssPKIObject_Unlock(object);
198
0
    return (newInstances ? PR_SUCCESS : PR_FAILURE);
199
0
}
200
201
NSS_IMPLEMENT PRBool
202
nssPKIObject_HasInstance(
203
    nssPKIObject *object,
204
    nssCryptokiObject *instance)
205
0
{
206
0
    PRUint32 i;
207
0
    PRBool hasIt = PR_FALSE;
208
0
    ;
209
0
    nssPKIObject_Lock(object);
210
0
    for (i = 0; i < object->numInstances; i++) {
211
0
        if (nssCryptokiObject_Equal(object->instances[i], instance)) {
212
0
            hasIt = PR_TRUE;
213
0
            break;
214
0
        }
215
0
    }
216
0
    nssPKIObject_Unlock(object);
217
0
    return hasIt;
218
0
}
219
220
NSS_IMPLEMENT PRStatus
221
nssPKIObject_RemoveInstanceForToken(
222
    nssPKIObject *object,
223
    NSSToken *token)
224
0
{
225
0
    PRUint32 i;
226
0
    nssCryptokiObject *instanceToRemove = NULL;
227
0
    nssPKIObject_Lock(object);
228
0
    if (object->numInstances == 0) {
229
0
        nssPKIObject_Unlock(object);
230
0
        return PR_SUCCESS;
231
0
    }
232
0
    for (i = 0; i < object->numInstances; i++) {
233
0
        if (object->instances[i]->token == token) {
234
0
            instanceToRemove = object->instances[i];
235
0
            object->instances[i] = object->instances[object->numInstances - 1];
236
0
            object->instances[object->numInstances - 1] = NULL;
237
0
            break;
238
0
        }
239
0
    }
240
0
    if (--object->numInstances > 0) {
241
0
        nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
242
0
                                                          nssCryptokiObject *,
243
0
                                                          object->numInstances);
244
0
        if (instances) {
245
0
            object->instances = instances;
246
0
        }
247
0
    } else {
248
0
        nss_ZFreeIf(object->instances);
249
0
    }
250
0
    nssCryptokiObject_Destroy(instanceToRemove);
251
0
    nssPKIObject_Unlock(object);
252
0
    return PR_SUCCESS;
253
0
}
254
255
/* this needs more thought on what will happen when there are multiple
256
 * instances
257
 */
258
NSS_IMPLEMENT PRStatus
259
nssPKIObject_DeleteStoredObject(
260
    nssPKIObject *object,
261
    NSSCallback *uhh,
262
    PRBool isFriendly)
263
0
{
264
0
    PRUint32 i, numNotDestroyed;
265
0
    PRStatus status = PR_SUCCESS;
266
0
    numNotDestroyed = 0;
267
0
    nssPKIObject_Lock(object);
268
0
    for (i = 0; i < object->numInstances; i++) {
269
0
        nssCryptokiObject *instance = object->instances[i];
270
0
        status = nssToken_DeleteStoredObject(instance);
271
0
        object->instances[i] = NULL;
272
0
        if (status == PR_SUCCESS) {
273
0
            nssCryptokiObject_Destroy(instance);
274
0
        } else {
275
0
            object->instances[numNotDestroyed++] = instance;
276
0
        }
277
0
    }
278
0
    if (numNotDestroyed == 0) {
279
0
        nss_ZFreeIf(object->instances);
280
0
        object->numInstances = 0;
281
0
    } else {
282
0
        object->numInstances = numNotDestroyed;
283
0
    }
284
0
    nssPKIObject_Unlock(object);
285
0
    return status;
286
0
}
287
288
NSS_IMPLEMENT NSSToken **
289
nssPKIObject_GetTokens(
290
    nssPKIObject *object,
291
    PRStatus *statusOpt)
292
0
{
293
0
    NSSToken **tokens = NULL;
294
0
    nssPKIObject_Lock(object);
295
0
    if (object->numInstances > 0) {
296
0
        tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
297
0
        if (tokens) {
298
0
            PRUint32 i;
299
0
            for (i = 0; i < object->numInstances; i++) {
300
0
                tokens[i] = nssToken_AddRef(object->instances[i]->token);
301
0
            }
302
0
        }
303
0
    }
304
0
    nssPKIObject_Unlock(object);
305
0
    if (statusOpt)
306
0
        *statusOpt = PR_SUCCESS; /* until more logic here */
307
0
    return tokens;
308
0
}
309
310
NSS_IMPLEMENT NSSUTF8 *
311
nssPKIObject_GetNicknameForToken(
312
    nssPKIObject *object,
313
    NSSToken *tokenOpt)
314
0
{
315
0
    PRUint32 i;
316
0
    NSSUTF8 *nickname = NULL;
317
0
    nssPKIObject_Lock(object);
318
0
    for (i = 0; i < object->numInstances; i++) {
319
0
        if ((!tokenOpt && object->instances[i]->label) ||
320
0
            (object->instances[i]->token == tokenOpt)) {
321
            /* Must copy, see bug 745548 */
322
0
            nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL);
323
0
            break;
324
0
        }
325
0
    }
326
0
    nssPKIObject_Unlock(object);
327
0
    return nickname;
328
0
}
329
330
NSS_IMPLEMENT nssCryptokiObject **
331
nssPKIObject_GetInstances(
332
    nssPKIObject *object)
333
0
{
334
0
    nssCryptokiObject **instances = NULL;
335
0
    PRUint32 i;
336
337
0
    nssPKIObject_Lock(object);
338
0
    if (object->numInstances == 0) {
339
0
        nssPKIObject_Unlock(object);
340
0
        return (nssCryptokiObject **)NULL;
341
0
    }
342
0
    instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *,
343
0
                              object->numInstances + 1);
344
0
    if (instances) {
345
0
        for (i = 0; i < object->numInstances; i++) {
346
0
            instances[i] = nssCryptokiObject_Clone(object->instances[i]);
347
0
        }
348
0
    }
349
0
    nssPKIObject_Unlock(object);
350
0
    return instances;
351
0
}
352
353
NSS_IMPLEMENT void
354
nssCertificateArray_Destroy(
355
    NSSCertificate **certs)
356
0
{
357
0
    if (certs) {
358
0
        NSSCertificate **certp;
359
0
        for (certp = certs; *certp; certp++) {
360
0
            if ((*certp)->decoding) {
361
0
                CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
362
0
                if (cc) {
363
0
                    CERT_DestroyCertificate(cc);
364
0
                }
365
0
                continue;
366
0
            }
367
0
            nssCertificate_Destroy(*certp);
368
0
        }
369
0
        nss_ZFreeIf(certs);
370
0
    }
371
0
}
372
373
NSS_IMPLEMENT void
374
NSSCertificateArray_Destroy(
375
    NSSCertificate **certs)
376
0
{
377
0
    nssCertificateArray_Destroy(certs);
378
0
}
379
380
NSS_IMPLEMENT NSSCertificate **
381
nssCertificateArray_Join(
382
    NSSCertificate **certs1,
383
    NSSCertificate **certs2)
384
0
{
385
0
    if (certs1 && certs2) {
386
0
        NSSCertificate **certs, **cp;
387
0
        PRUint32 count = 0;
388
0
        PRUint32 count1 = 0;
389
0
        cp = certs1;
390
0
        while (*cp++)
391
0
            count1++;
392
0
        count = count1;
393
0
        cp = certs2;
394
0
        while (*cp++)
395
0
            count++;
396
0
        certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
397
0
        if (!certs) {
398
0
            nss_ZFreeIf(certs1);
399
0
            nss_ZFreeIf(certs2);
400
0
            return (NSSCertificate **)NULL;
401
0
        }
402
0
        for (cp = certs2; *cp; cp++, count1++) {
403
0
            certs[count1] = *cp;
404
0
        }
405
0
        nss_ZFreeIf(certs2);
406
0
        return certs;
407
0
    } else if (certs1) {
408
0
        return certs1;
409
0
    } else {
410
0
        return certs2;
411
0
    }
412
0
}
413
414
NSS_IMPLEMENT NSSCertificate *
415
nssCertificateArray_FindBestCertificate(
416
    NSSCertificate **certs,
417
    NSSTime *timeOpt,
418
    const NSSUsage *usage,
419
    NSSPolicies *policiesOpt)
420
0
{
421
0
    NSSCertificate *bestCert = NULL;
422
0
    nssDecodedCert *bestdc = NULL;
423
0
    NSSTime *time, sTime;
424
0
    PRBool bestCertMatches = PR_FALSE;
425
0
    PRBool thisCertMatches;
426
0
    PRBool bestCertIsValidAtTime = PR_FALSE;
427
0
    PRBool bestCertIsTrusted = PR_FALSE;
428
429
0
    if (timeOpt) {
430
0
        time = timeOpt;
431
0
    } else {
432
0
        NSSTime_Now(&sTime);
433
0
        time = &sTime;
434
0
    }
435
0
    if (!certs) {
436
0
        return (NSSCertificate *)NULL;
437
0
    }
438
0
    for (; *certs; certs++) {
439
0
        nssDecodedCert *dc;
440
0
        NSSCertificate *c = *certs;
441
0
        dc = nssCertificate_GetDecoding(c);
442
0
        if (!dc)
443
0
            continue;
444
0
        thisCertMatches = dc->matchUsage(dc, usage);
445
0
        if (!bestCert) {
446
            /* always take the first cert, but remember whether or not
447
             * the usage matched
448
             */
449
0
            bestCert = nssCertificate_AddRef(c);
450
0
            bestCertMatches = thisCertMatches;
451
0
            bestdc = dc;
452
0
            continue;
453
0
        } else {
454
0
            if (bestCertMatches && !thisCertMatches) {
455
                /* if already have a cert for this usage, and if this cert
456
                 * doesn't have the correct usage, continue
457
                 */
458
0
                continue;
459
0
            } else if (!bestCertMatches && thisCertMatches) {
460
                /* this one does match usage, replace the other */
461
0
                nssCertificate_Destroy(bestCert);
462
0
                bestCert = nssCertificate_AddRef(c);
463
0
                bestCertMatches = thisCertMatches;
464
0
                bestdc = dc;
465
0
                continue;
466
0
            }
467
            /* this cert match as well as any cert we've found so far,
468
             * defer to time/policies
469
             * */
470
0
        }
471
        /* time */
472
0
        if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) {
473
            /* The current best cert is valid at time */
474
0
            bestCertIsValidAtTime = PR_TRUE;
475
0
            if (!dc->isValidAtTime(dc, time)) {
476
                /* If the new cert isn't valid at time, it's not better */
477
0
                continue;
478
0
            }
479
0
        } else {
480
            /* The current best cert is not valid at time */
481
0
            if (dc->isValidAtTime(dc, time)) {
482
                /* If the new cert is valid at time, it's better */
483
0
                nssCertificate_Destroy(bestCert);
484
0
                bestCert = nssCertificate_AddRef(c);
485
0
                bestdc = dc;
486
0
                bestCertIsValidAtTime = PR_TRUE;
487
0
                continue;
488
0
            }
489
0
        }
490
        /* Either they are both valid at time, or neither valid.
491
         * If only one is trusted for this usage, take it.
492
         */
493
0
        if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) {
494
0
            bestCertIsTrusted = PR_TRUE;
495
0
            if (!dc->isTrustedForUsage(dc, usage)) {
496
0
                continue;
497
0
            }
498
0
        } else {
499
            /* The current best cert is not trusted */
500
0
            if (dc->isTrustedForUsage(dc, usage)) {
501
                /* If the new cert is trusted, it's better */
502
0
                nssCertificate_Destroy(bestCert);
503
0
                bestCert = nssCertificate_AddRef(c);
504
0
                bestdc = dc;
505
0
                bestCertIsTrusted = PR_TRUE;
506
0
                continue;
507
0
            }
508
0
        }
509
        /* Otherwise, take the newer one. */
510
0
        if (!bestdc->isNewerThan(bestdc, dc)) {
511
0
            nssCertificate_Destroy(bestCert);
512
0
            bestCert = nssCertificate_AddRef(c);
513
0
            bestdc = dc;
514
0
            continue;
515
0
        }
516
        /* policies */
517
        /* XXX later -- defer to policies */
518
0
    }
519
0
    return bestCert;
520
0
}
521
522
NSS_IMPLEMENT PRStatus
523
nssCertificateArray_Traverse(
524
    NSSCertificate **certs,
525
    PRStatus (*callback)(NSSCertificate *c, void *arg),
526
    void *arg)
527
0
{
528
0
    PRStatus status = PR_SUCCESS;
529
0
    if (certs) {
530
0
        NSSCertificate **certp;
531
0
        for (certp = certs; *certp; certp++) {
532
0
            status = (*callback)(*certp, arg);
533
0
            if (status != PR_SUCCESS) {
534
0
                break;
535
0
            }
536
0
        }
537
0
    }
538
0
    return status;
539
0
}
540
541
NSS_IMPLEMENT void
542
nssCRLArray_Destroy(
543
    NSSCRL **crls)
544
0
{
545
0
    if (crls) {
546
0
        NSSCRL **crlp;
547
0
        for (crlp = crls; *crlp; crlp++) {
548
0
            nssCRL_Destroy(*crlp);
549
0
        }
550
0
        nss_ZFreeIf(crls);
551
0
    }
552
0
}
553
554
/*
555
 * Object collections
556
 */
557
558
typedef enum {
559
    pkiObjectType_Certificate = 0,
560
    pkiObjectType_CRL = 1,
561
    pkiObjectType_PrivateKey = 2,
562
    pkiObjectType_PublicKey = 3
563
} pkiObjectType;
564
565
/* Each object is defined by a set of items that uniquely identify it.
566
 * Here are the uid sets:
567
 *
568
 * NSSCertificate ==>  { issuer, serial }
569
 * NSSPrivateKey
570
 *         (RSA) ==> { modulus, public exponent }
571
 *
572
 */
573
0
#define MAX_ITEMS_FOR_UID 2
574
575
/* pkiObjectCollectionNode
576
 *
577
 * A node in the collection is the set of unique identifiers for a single
578
 * object, along with either the actual object or a proto-object.
579
 */
580
typedef struct
581
{
582
    PRCList link;
583
    PRBool haveObject;
584
    nssPKIObject *object;
585
    NSSItem uid[MAX_ITEMS_FOR_UID];
586
} pkiObjectCollectionNode;
587
588
/* nssPKIObjectCollection
589
 *
590
 * The collection is the set of all objects, plus the interfaces needed
591
 * to manage the objects.
592
 *
593
 */
594
struct nssPKIObjectCollectionStr {
595
    NSSArena *arena;
596
    NSSTrustDomain *td;
597
    NSSCryptoContext *cc;
598
    PRCList head; /* list of pkiObjectCollectionNode's */
599
    PRUint32 size;
600
    pkiObjectType objectType;
601
    void (*destroyObject)(nssPKIObject *o);
602
    PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
603
    PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid,
604
                                   NSSArena *arena);
605
    nssPKIObject *(*createObject)(nssPKIObject *o);
606
    nssPKILockType lockType; /* type of lock to use for new proto-objects */
607
};
608
609
static nssPKIObjectCollection *
610
nssPKIObjectCollection_Create(
611
    NSSTrustDomain *td,
612
    NSSCryptoContext *ccOpt,
613
    nssPKILockType lockType)
614
0
{
615
0
    NSSArena *arena;
616
0
    nssPKIObjectCollection *rvCollection = NULL;
617
0
    arena = nssArena_Create();
618
0
    if (!arena) {
619
0
        return (nssPKIObjectCollection *)NULL;
620
0
    }
621
0
    rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
622
0
    if (!rvCollection) {
623
0
        goto loser;
624
0
    }
625
0
    PR_INIT_CLIST(&rvCollection->head);
626
0
    rvCollection->arena = arena;
627
0
    rvCollection->td = td; /* XXX */
628
0
    rvCollection->cc = ccOpt;
629
0
    rvCollection->lockType = lockType;
630
0
    return rvCollection;
631
0
loser:
632
0
    nssArena_Destroy(arena);
633
0
    return (nssPKIObjectCollection *)NULL;
634
0
}
635
636
NSS_IMPLEMENT void
637
nssPKIObjectCollection_Destroy(
638
    nssPKIObjectCollection *collection)
639
0
{
640
0
    if (collection) {
641
0
        PRCList *link;
642
0
        pkiObjectCollectionNode *node;
643
        /* first destroy any objects in the collection */
644
0
        link = PR_NEXT_LINK(&collection->head);
645
0
        while (link != &collection->head) {
646
0
            node = (pkiObjectCollectionNode *)link;
647
0
            if (node->haveObject) {
648
0
                (*collection->destroyObject)(node->object);
649
0
            } else {
650
0
                nssPKIObject_Destroy(node->object);
651
0
            }
652
0
            link = PR_NEXT_LINK(link);
653
0
        }
654
        /* then destroy it */
655
0
        nssArena_Destroy(collection->arena);
656
0
    }
657
0
}
658
659
NSS_IMPLEMENT PRUint32
660
nssPKIObjectCollection_Count(
661
    nssPKIObjectCollection *collection)
662
0
{
663
0
    return collection->size;
664
0
}
665
666
NSS_IMPLEMENT PRStatus
667
nssPKIObjectCollection_AddObject(
668
    nssPKIObjectCollection *collection,
669
    nssPKIObject *object)
670
0
{
671
0
    pkiObjectCollectionNode *node;
672
0
    node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
673
0
    if (!node) {
674
0
        return PR_FAILURE;
675
0
    }
676
0
    node->haveObject = PR_TRUE;
677
0
    node->object = nssPKIObject_AddRef(object);
678
0
    (*collection->getUIDFromObject)(object, node->uid);
679
0
    PR_INIT_CLIST(&node->link);
680
0
    PR_INSERT_BEFORE(&node->link, &collection->head);
681
0
    collection->size++;
682
0
    return PR_SUCCESS;
683
0
}
684
685
static pkiObjectCollectionNode *
686
find_instance_in_collection(
687
    nssPKIObjectCollection *collection,
688
    nssCryptokiObject *instance)
689
0
{
690
0
    PRCList *link;
691
0
    pkiObjectCollectionNode *node;
692
0
    link = PR_NEXT_LINK(&collection->head);
693
0
    while (link != &collection->head) {
694
0
        node = (pkiObjectCollectionNode *)link;
695
0
        if (nssPKIObject_HasInstance(node->object, instance)) {
696
0
            return node;
697
0
        }
698
0
        link = PR_NEXT_LINK(link);
699
0
    }
700
0
    return (pkiObjectCollectionNode *)NULL;
701
0
}
702
703
static pkiObjectCollectionNode *
704
find_object_in_collection(
705
    nssPKIObjectCollection *collection,
706
    NSSItem *uid)
707
0
{
708
0
    PRUint32 i;
709
0
    PRStatus status;
710
0
    PRCList *link;
711
0
    pkiObjectCollectionNode *node;
712
0
    link = PR_NEXT_LINK(&collection->head);
713
0
    while (link != &collection->head) {
714
0
        node = (pkiObjectCollectionNode *)link;
715
0
        for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
716
0
            if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
717
0
                break;
718
0
            }
719
0
        }
720
0
        if (i == MAX_ITEMS_FOR_UID) {
721
0
            return node;
722
0
        }
723
0
        link = PR_NEXT_LINK(link);
724
0
    }
725
0
    return (pkiObjectCollectionNode *)NULL;
726
0
}
727
728
static pkiObjectCollectionNode *
729
add_object_instance(
730
    nssPKIObjectCollection *collection,
731
    nssCryptokiObject *instance,
732
    PRBool *foundIt)
733
0
{
734
0
    PRUint32 i;
735
0
    PRStatus status;
736
0
    pkiObjectCollectionNode *node;
737
0
    nssArenaMark *mark = NULL;
738
0
    NSSItem uid[MAX_ITEMS_FOR_UID];
739
0
    nsslibc_memset(uid, 0, sizeof uid);
740
    /* The list is traversed twice, first (here) looking to match the
741
     * { token, handle } tuple, and if that is not found, below a search
742
     * for unique identifier is done.  Here, a match means this exact object
743
     * instance is already in the collection, and we have nothing to do.
744
     */
745
0
    *foundIt = PR_FALSE;
746
0
    node = find_instance_in_collection(collection, instance);
747
0
    if (node) {
748
        /* The collection is assumed to take over the instance.  Since we
749
         * are not using it, it must be destroyed.
750
         */
751
0
        nssCryptokiObject_Destroy(instance);
752
0
        *foundIt = PR_TRUE;
753
0
        return node;
754
0
    }
755
0
    mark = nssArena_Mark(collection->arena);
756
0
    if (!mark) {
757
0
        goto loser;
758
0
    }
759
0
    status = (*collection->getUIDFromInstance)(instance, uid,
760
0
                                               collection->arena);
761
0
    if (status != PR_SUCCESS) {
762
0
        goto loser;
763
0
    }
764
    /* Search for unique identifier.  A match here means the object exists
765
     * in the collection, but does not have this instance, so the instance
766
     * needs to be added.
767
     */
768
0
    node = find_object_in_collection(collection, uid);
769
0
    if (node) {
770
        /* This is an object with multiple instances */
771
0
        status = nssPKIObject_AddInstance(node->object, instance);
772
0
    } else {
773
        /* This is a completely new object.  Create a node for it. */
774
0
        node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
775
0
        if (!node) {
776
0
            goto loser;
777
0
        }
778
0
        node->object = nssPKIObject_Create(NULL, instance,
779
0
                                           collection->td, collection->cc,
780
0
                                           collection->lockType);
781
0
        if (!node->object) {
782
0
            goto loser;
783
0
        }
784
0
        for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
785
0
            node->uid[i] = uid[i];
786
0
        }
787
0
        node->haveObject = PR_FALSE;
788
0
        PR_INIT_CLIST(&node->link);
789
0
        PR_INSERT_BEFORE(&node->link, &collection->head);
790
0
        collection->size++;
791
0
        status = PR_SUCCESS;
792
0
    }
793
0
    nssArena_Unmark(collection->arena, mark);
794
0
    return node;
795
0
loser:
796
0
    if (mark) {
797
0
        nssArena_Release(collection->arena, mark);
798
0
    }
799
0
    nssCryptokiObject_Destroy(instance);
800
0
    return (pkiObjectCollectionNode *)NULL;
801
0
}
802
803
NSS_IMPLEMENT PRStatus
804
nssPKIObjectCollection_AddInstances(
805
    nssPKIObjectCollection *collection,
806
    nssCryptokiObject **instances,
807
    PRUint32 numInstances)
808
0
{
809
0
    PRStatus status = PR_SUCCESS;
810
0
    PRUint32 i = 0;
811
0
    PRBool foundIt;
812
0
    pkiObjectCollectionNode *node;
813
0
    if (instances) {
814
0
        while ((!numInstances || i < numInstances) && *instances) {
815
0
            if (status == PR_SUCCESS) {
816
0
                node = add_object_instance(collection, *instances, &foundIt);
817
0
                if (node == NULL) {
818
                    /* add_object_instance freed the current instance */
819
                    /* free the remaining instances */
820
0
                    status = PR_FAILURE;
821
0
                }
822
0
            } else {
823
0
                nssCryptokiObject_Destroy(*instances);
824
0
            }
825
0
            instances++;
826
0
            i++;
827
0
        }
828
0
    }
829
0
    return status;
830
0
}
831
832
static void
833
nssPKIObjectCollection_RemoveNode(
834
    nssPKIObjectCollection *collection,
835
    pkiObjectCollectionNode *node)
836
0
{
837
0
    PR_REMOVE_LINK(&node->link);
838
0
    collection->size--;
839
0
}
840
841
static PRStatus
842
nssPKIObjectCollection_GetObjects(
843
    nssPKIObjectCollection *collection,
844
    nssPKIObject **rvObjects,
845
    PRUint32 rvSize)
846
0
{
847
0
    PRUint32 i = 0;
848
0
    PRCList *link = PR_NEXT_LINK(&collection->head);
849
0
    pkiObjectCollectionNode *node;
850
0
    int error = 0;
851
0
    while ((i < rvSize) && (link != &collection->head)) {
852
0
        node = (pkiObjectCollectionNode *)link;
853
0
        if (!node->haveObject) {
854
            /* Convert the proto-object to an object */
855
0
            node->object = (*collection->createObject)(node->object);
856
0
            if (!node->object) {
857
0
                link = PR_NEXT_LINK(link);
858
                /*remove bogus object from list*/
859
0
                nssPKIObjectCollection_RemoveNode(collection, node);
860
0
                error++;
861
0
                continue;
862
0
            }
863
0
            node->haveObject = PR_TRUE;
864
0
        }
865
0
        rvObjects[i++] = nssPKIObject_AddRef(node->object);
866
0
        link = PR_NEXT_LINK(link);
867
0
    }
868
0
    if (!error && *rvObjects == NULL) {
869
0
        nss_SetError(NSS_ERROR_NOT_FOUND);
870
0
    }
871
0
    return PR_SUCCESS;
872
0
}
873
874
NSS_IMPLEMENT PRStatus
875
nssPKIObjectCollection_Traverse(
876
    nssPKIObjectCollection *collection,
877
    nssPKIObjectCallback *callback)
878
0
{
879
0
    PRCList *link = PR_NEXT_LINK(&collection->head);
880
0
    pkiObjectCollectionNode *node;
881
0
    while (link != &collection->head) {
882
0
        node = (pkiObjectCollectionNode *)link;
883
0
        if (!node->haveObject) {
884
0
            node->object = (*collection->createObject)(node->object);
885
0
            if (!node->object) {
886
0
                link = PR_NEXT_LINK(link);
887
                /*remove bogus object from list*/
888
0
                nssPKIObjectCollection_RemoveNode(collection, node);
889
0
                continue;
890
0
            }
891
0
            node->haveObject = PR_TRUE;
892
0
        }
893
0
        switch (collection->objectType) {
894
0
            case pkiObjectType_Certificate:
895
0
                (void)(*callback->func.cert)((NSSCertificate *)node->object,
896
0
                                             callback->arg);
897
0
                break;
898
0
            case pkiObjectType_CRL:
899
0
                (void)(*callback->func.crl)((NSSCRL *)node->object,
900
0
                                            callback->arg);
901
0
                break;
902
0
            case pkiObjectType_PrivateKey:
903
0
                (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object,
904
0
                                              callback->arg);
905
0
                break;
906
0
            case pkiObjectType_PublicKey:
907
0
                (void)(*callback->func.pbkey)((NSSPublicKey *)node->object,
908
0
                                              callback->arg);
909
0
                break;
910
0
        }
911
0
        link = PR_NEXT_LINK(link);
912
0
    }
913
0
    return PR_SUCCESS;
914
0
}
915
916
NSS_IMPLEMENT PRStatus
917
nssPKIObjectCollection_AddInstanceAsObject(
918
    nssPKIObjectCollection *collection,
919
    nssCryptokiObject *instance)
920
0
{
921
0
    pkiObjectCollectionNode *node;
922
0
    PRBool foundIt;
923
0
    node = add_object_instance(collection, instance, &foundIt);
924
0
    if (node == NULL) {
925
0
        return PR_FAILURE;
926
0
    }
927
0
    if (!node->haveObject) {
928
0
        nssPKIObject *original = node->object;
929
0
        node->object = (*collection->createObject)(node->object);
930
0
        if (!node->object) {
931
            /*remove bogus object from list*/
932
0
            nssPKIObject_Destroy(original);
933
0
            nssPKIObjectCollection_RemoveNode(collection, node);
934
0
            return PR_FAILURE;
935
0
        }
936
0
        node->haveObject = PR_TRUE;
937
0
    } else if (!foundIt) {
938
        /* The instance was added to a pre-existing node.  This
939
         * function is *only* being used for certificates, and having
940
         * multiple instances of certs in 3.X requires updating the
941
         * CERTCertificate.
942
         * But only do it if it was a new instance!!!  If the same instance
943
         * is encountered, we set *foundIt to true.  Detect that here and
944
         * ignore it.
945
         */
946
0
        STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
947
0
    }
948
0
    return PR_SUCCESS;
949
0
}
950
951
/*
952
 * Certificate collections
953
 */
954
955
static void
956
cert_destroyObject(nssPKIObject *o)
957
0
{
958
0
    NSSCertificate *c = (NSSCertificate *)o;
959
0
    if (c->decoding) {
960
0
        CERTCertificate *cc = STAN_GetCERTCertificate(c);
961
0
        if (cc) {
962
0
            CERT_DestroyCertificate(cc);
963
0
            return;
964
0
        } /* else destroy it as NSSCertificate below */
965
0
    }
966
0
    nssCertificate_Destroy(c);
967
0
}
968
969
static PRStatus
970
cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
971
0
{
972
0
    NSSCertificate *c = (NSSCertificate *)o;
973
    /* The builtins are still returning decoded serial numbers.  Until
974
     * this compatibility issue is resolved, use the full DER of the
975
     * cert to uniquely identify it.
976
     */
977
0
    NSSDER *derCert;
978
0
    derCert = nssCertificate_GetEncoding(c);
979
0
    uid[0].data = NULL;
980
0
    uid[0].size = 0;
981
0
    uid[1].data = NULL;
982
0
    uid[1].size = 0;
983
0
    if (derCert != NULL) {
984
0
        uid[0] = *derCert;
985
0
    }
986
0
    return PR_SUCCESS;
987
0
}
988
989
static PRStatus
990
cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
991
                        NSSArena *arena)
992
0
{
993
    /* The builtins are still returning decoded serial numbers.  Until
994
     * this compatibility issue is resolved, use the full DER of the
995
     * cert to uniquely identify it.
996
     */
997
0
    uid[1].data = NULL;
998
0
    uid[1].size = 0;
999
0
    return nssCryptokiCertificate_GetAttributes(instance,
1000
0
                                                NULL,    /* XXX sessionOpt */
1001
0
                                                arena,   /* arena    */
1002
0
                                                NULL,    /* type     */
1003
0
                                                NULL,    /* id       */
1004
0
                                                &uid[0], /* encoding */
1005
0
                                                NULL,    /* issuer   */
1006
0
                                                NULL,    /* serial   */
1007
0
                                                NULL);   /* subject  */
1008
0
}
1009
1010
static nssPKIObject *
1011
cert_createObject(nssPKIObject *o)
1012
0
{
1013
0
    NSSCertificate *cert;
1014
0
    cert = nssCertificate_Create(o);
1015
    /*    if (STAN_GetCERTCertificate(cert) == NULL) {
1016
        nssCertificate_Destroy(cert);
1017
        return (nssPKIObject *)NULL;
1018
    } */
1019
    /* In 3.4, have to maintain uniqueness of cert pointers by caching all
1020
     * certs.  Cache the cert here, before returning.  If it is already
1021
     * cached, take the cached entry.
1022
     */
1023
0
    {
1024
0
        NSSTrustDomain *td = o->trustDomain;
1025
0
        nssTrustDomain_AddCertsToCache(td, &cert, 1);
1026
0
    }
1027
0
    return (nssPKIObject *)cert;
1028
0
}
1029
1030
NSS_IMPLEMENT nssPKIObjectCollection *
1031
nssCertificateCollection_Create(
1032
    NSSTrustDomain *td,
1033
    NSSCertificate **certsOpt)
1034
0
{
1035
0
    nssPKIObjectCollection *collection;
1036
0
    collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
1037
0
    if (!collection) {
1038
0
        return NULL;
1039
0
    }
1040
0
    collection->objectType = pkiObjectType_Certificate;
1041
0
    collection->destroyObject = cert_destroyObject;
1042
0
    collection->getUIDFromObject = cert_getUIDFromObject;
1043
0
    collection->getUIDFromInstance = cert_getUIDFromInstance;
1044
0
    collection->createObject = cert_createObject;
1045
0
    if (certsOpt) {
1046
0
        for (; *certsOpt; certsOpt++) {
1047
0
            nssPKIObject *object = (nssPKIObject *)(*certsOpt);
1048
0
            (void)nssPKIObjectCollection_AddObject(collection, object);
1049
0
        }
1050
0
    }
1051
0
    return collection;
1052
0
}
1053
1054
NSS_IMPLEMENT NSSCertificate **
1055
nssPKIObjectCollection_GetCertificates(
1056
    nssPKIObjectCollection *collection,
1057
    NSSCertificate **rvOpt,
1058
    PRUint32 maximumOpt,
1059
    NSSArena *arenaOpt)
1060
0
{
1061
0
    PRStatus status;
1062
0
    PRUint32 rvSize;
1063
0
    PRBool allocated = PR_FALSE;
1064
0
    if (collection->size == 0) {
1065
0
        return (NSSCertificate **)NULL;
1066
0
    }
1067
0
    if (maximumOpt == 0) {
1068
0
        rvSize = collection->size;
1069
0
    } else {
1070
0
        rvSize = PR_MIN(collection->size, maximumOpt);
1071
0
    }
1072
0
    if (!rvOpt) {
1073
0
        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
1074
0
        if (!rvOpt) {
1075
0
            return (NSSCertificate **)NULL;
1076
0
        }
1077
0
        allocated = PR_TRUE;
1078
0
    }
1079
0
    status = nssPKIObjectCollection_GetObjects(collection,
1080
0
                                               (nssPKIObject **)rvOpt,
1081
0
                                               rvSize);
1082
0
    if (status != PR_SUCCESS) {
1083
0
        if (allocated) {
1084
0
            nss_ZFreeIf(rvOpt);
1085
0
        }
1086
0
        return (NSSCertificate **)NULL;
1087
0
    }
1088
0
    return rvOpt;
1089
0
}
1090
1091
/*
1092
 * CRL/KRL collections
1093
 */
1094
1095
static void
1096
crl_destroyObject(nssPKIObject *o)
1097
0
{
1098
0
    NSSCRL *crl = (NSSCRL *)o;
1099
0
    nssCRL_Destroy(crl);
1100
0
}
1101
1102
static PRStatus
1103
crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
1104
0
{
1105
0
    NSSCRL *crl = (NSSCRL *)o;
1106
0
    NSSDER *encoding;
1107
0
    encoding = nssCRL_GetEncoding(crl);
1108
0
    if (!encoding) {
1109
0
        nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
1110
0
        return PR_FALSE;
1111
0
    }
1112
0
    uid[0] = *encoding;
1113
0
    uid[1].data = NULL;
1114
0
    uid[1].size = 0;
1115
0
    return PR_SUCCESS;
1116
0
}
1117
1118
static PRStatus
1119
crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
1120
                       NSSArena *arena)
1121
0
{
1122
0
    return nssCryptokiCRL_GetAttributes(instance,
1123
0
                                        NULL,    /* XXX sessionOpt */
1124
0
                                        arena,   /* arena    */
1125
0
                                        &uid[0], /* encoding */
1126
0
                                        NULL,    /* subject  */
1127
0
                                        NULL,    /* class    */
1128
0
                                        NULL,    /* url      */
1129
0
                                        NULL);   /* isKRL    */
1130
0
}
1131
1132
static nssPKIObject *
1133
crl_createObject(nssPKIObject *o)
1134
0
{
1135
0
    return (nssPKIObject *)nssCRL_Create(o);
1136
0
}
1137
1138
NSS_IMPLEMENT nssPKIObjectCollection *
1139
nssCRLCollection_Create(
1140
    NSSTrustDomain *td,
1141
    NSSCRL **crlsOpt)
1142
0
{
1143
0
    nssPKIObjectCollection *collection;
1144
0
    collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
1145
0
    if (!collection) {
1146
0
        return NULL;
1147
0
    }
1148
0
    collection->objectType = pkiObjectType_CRL;
1149
0
    collection->destroyObject = crl_destroyObject;
1150
0
    collection->getUIDFromObject = crl_getUIDFromObject;
1151
0
    collection->getUIDFromInstance = crl_getUIDFromInstance;
1152
0
    collection->createObject = crl_createObject;
1153
0
    if (crlsOpt) {
1154
0
        for (; *crlsOpt; crlsOpt++) {
1155
0
            nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
1156
0
            (void)nssPKIObjectCollection_AddObject(collection, object);
1157
0
        }
1158
0
    }
1159
0
    return collection;
1160
0
}
1161
1162
NSS_IMPLEMENT NSSCRL **
1163
nssPKIObjectCollection_GetCRLs(
1164
    nssPKIObjectCollection *collection,
1165
    NSSCRL **rvOpt,
1166
    PRUint32 maximumOpt,
1167
    NSSArena *arenaOpt)
1168
0
{
1169
0
    PRStatus status;
1170
0
    PRUint32 rvSize;
1171
0
    PRBool allocated = PR_FALSE;
1172
0
    if (collection->size == 0) {
1173
0
        return (NSSCRL **)NULL;
1174
0
    }
1175
0
    if (maximumOpt == 0) {
1176
0
        rvSize = collection->size;
1177
0
    } else {
1178
0
        rvSize = PR_MIN(collection->size, maximumOpt);
1179
0
    }
1180
0
    if (!rvOpt) {
1181
0
        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
1182
0
        if (!rvOpt) {
1183
0
            return (NSSCRL **)NULL;
1184
0
        }
1185
0
        allocated = PR_TRUE;
1186
0
    }
1187
0
    status = nssPKIObjectCollection_GetObjects(collection,
1188
0
                                               (nssPKIObject **)rvOpt,
1189
0
                                               rvSize);
1190
0
    if (status != PR_SUCCESS) {
1191
0
        if (allocated) {
1192
0
            nss_ZFreeIf(rvOpt);
1193
0
        }
1194
0
        return (NSSCRL **)NULL;
1195
0
    }
1196
0
    return rvOpt;
1197
0
}
1198
1199
/* how bad would it be to have a static now sitting around, updated whenever
1200
 * this was called?  would avoid repeated allocs...
1201
 */
1202
NSS_IMPLEMENT NSSTime *
1203
NSSTime_Now(NSSTime *timeOpt)
1204
0
{
1205
0
    return NSSTime_SetPRTime(timeOpt, PR_Now());
1206
0
}
1207
1208
NSS_IMPLEMENT NSSTime *
1209
NSSTime_SetPRTime(
1210
    NSSTime *timeOpt,
1211
    PRTime prTime)
1212
0
{
1213
0
    NSSTime *rvTime;
1214
0
    rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
1215
0
    if (rvTime) {
1216
0
        rvTime->prTime = prTime;
1217
0
    }
1218
0
    return rvTime;
1219
0
}
1220
1221
NSS_IMPLEMENT PRTime
1222
NSSTime_GetPRTime(
1223
    NSSTime *time)
1224
0
{
1225
0
    return time->prTime;
1226
0
}