Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/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
0
    if (object->numInstances == 0) {
337
0
        return (nssCryptokiObject **)NULL;
338
0
    }
339
0
    nssPKIObject_Lock(object);
340
0
    instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *,
341
0
                              object->numInstances + 1);
342
0
    if (instances) {
343
0
        for (i = 0; i < object->numInstances; i++) {
344
0
            instances[i] = nssCryptokiObject_Clone(object->instances[i]);
345
0
        }
346
0
    }
347
0
    nssPKIObject_Unlock(object);
348
0
    return instances;
349
0
}
350
351
NSS_IMPLEMENT void
352
nssCertificateArray_Destroy(
353
    NSSCertificate **certs)
354
0
{
355
0
    if (certs) {
356
0
        NSSCertificate **certp;
357
0
        for (certp = certs; *certp; certp++) {
358
0
            if ((*certp)->decoding) {
359
0
                CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
360
0
                if (cc) {
361
0
                    CERT_DestroyCertificate(cc);
362
0
                }
363
0
                continue;
364
0
            }
365
0
            nssCertificate_Destroy(*certp);
366
0
        }
367
0
        nss_ZFreeIf(certs);
368
0
    }
369
0
}
370
371
NSS_IMPLEMENT void
372
NSSCertificateArray_Destroy(
373
    NSSCertificate **certs)
374
0
{
375
0
    nssCertificateArray_Destroy(certs);
376
0
}
377
378
NSS_IMPLEMENT NSSCertificate **
379
nssCertificateArray_Join(
380
    NSSCertificate **certs1,
381
    NSSCertificate **certs2)
382
0
{
383
0
    if (certs1 && certs2) {
384
0
        NSSCertificate **certs, **cp;
385
0
        PRUint32 count = 0;
386
0
        PRUint32 count1 = 0;
387
0
        cp = certs1;
388
0
        while (*cp++)
389
0
            count1++;
390
0
        count = count1;
391
0
        cp = certs2;
392
0
        while (*cp++)
393
0
            count++;
394
0
        certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
395
0
        if (!certs) {
396
0
            nss_ZFreeIf(certs1);
397
0
            nss_ZFreeIf(certs2);
398
0
            return (NSSCertificate **)NULL;
399
0
        }
400
0
        for (cp = certs2; *cp; cp++, count1++) {
401
0
            certs[count1] = *cp;
402
0
        }
403
0
        nss_ZFreeIf(certs2);
404
0
        return certs;
405
0
    } else if (certs1) {
406
0
        return certs1;
407
0
    } else {
408
0
        return certs2;
409
0
    }
410
0
}
411
412
NSS_IMPLEMENT NSSCertificate *
413
nssCertificateArray_FindBestCertificate(
414
    NSSCertificate **certs,
415
    NSSTime *timeOpt,
416
    const NSSUsage *usage,
417
    NSSPolicies *policiesOpt)
418
0
{
419
0
    NSSCertificate *bestCert = NULL;
420
0
    nssDecodedCert *bestdc = NULL;
421
0
    NSSTime *time, sTime;
422
0
    PRBool bestCertMatches = PR_FALSE;
423
0
    PRBool thisCertMatches;
424
0
    PRBool bestCertIsValidAtTime = PR_FALSE;
425
0
    PRBool bestCertIsTrusted = PR_FALSE;
426
427
0
    if (timeOpt) {
428
0
        time = timeOpt;
429
0
    } else {
430
0
        NSSTime_Now(&sTime);
431
0
        time = &sTime;
432
0
    }
433
0
    if (!certs) {
434
0
        return (NSSCertificate *)NULL;
435
0
    }
436
0
    for (; *certs; certs++) {
437
0
        nssDecodedCert *dc;
438
0
        NSSCertificate *c = *certs;
439
0
        dc = nssCertificate_GetDecoding(c);
440
0
        if (!dc)
441
0
            continue;
442
0
        thisCertMatches = dc->matchUsage(dc, usage);
443
0
        if (!bestCert) {
444
            /* always take the first cert, but remember whether or not
445
             * the usage matched
446
             */
447
0
            bestCert = nssCertificate_AddRef(c);
448
0
            bestCertMatches = thisCertMatches;
449
0
            bestdc = dc;
450
0
            continue;
451
0
        } else {
452
0
            if (bestCertMatches && !thisCertMatches) {
453
                /* if already have a cert for this usage, and if this cert
454
                 * doesn't have the correct usage, continue
455
                 */
456
0
                continue;
457
0
            } else if (!bestCertMatches && thisCertMatches) {
458
                /* this one does match usage, replace the other */
459
0
                nssCertificate_Destroy(bestCert);
460
0
                bestCert = nssCertificate_AddRef(c);
461
0
                bestCertMatches = thisCertMatches;
462
0
                bestdc = dc;
463
0
                continue;
464
0
            }
465
            /* this cert match as well as any cert we've found so far,
466
             * defer to time/policies
467
             * */
468
0
        }
469
        /* time */
470
0
        if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) {
471
            /* The current best cert is valid at time */
472
0
            bestCertIsValidAtTime = PR_TRUE;
473
0
            if (!dc->isValidAtTime(dc, time)) {
474
                /* If the new cert isn't valid at time, it's not better */
475
0
                continue;
476
0
            }
477
0
        } else {
478
            /* The current best cert is not valid at time */
479
0
            if (dc->isValidAtTime(dc, time)) {
480
                /* If the new cert is valid at time, it's better */
481
0
                nssCertificate_Destroy(bestCert);
482
0
                bestCert = nssCertificate_AddRef(c);
483
0
                bestdc = dc;
484
0
                bestCertIsValidAtTime = PR_TRUE;
485
0
                continue;
486
0
            }
487
0
        }
488
        /* Either they are both valid at time, or neither valid.
489
         * If only one is trusted for this usage, take it.
490
         */
491
0
        if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) {
492
0
            bestCertIsTrusted = PR_TRUE;
493
0
            if (!dc->isTrustedForUsage(dc, usage)) {
494
0
                continue;
495
0
            }
496
0
        } else {
497
            /* The current best cert is not trusted */
498
0
            if (dc->isTrustedForUsage(dc, usage)) {
499
                /* If the new cert is trusted, it's better */
500
0
                nssCertificate_Destroy(bestCert);
501
0
                bestCert = nssCertificate_AddRef(c);
502
0
                bestdc = dc;
503
0
                bestCertIsTrusted = PR_TRUE;
504
0
                continue;
505
0
            }
506
0
        }
507
        /* Otherwise, take the newer one. */
508
0
        if (!bestdc->isNewerThan(bestdc, dc)) {
509
0
            nssCertificate_Destroy(bestCert);
510
0
            bestCert = nssCertificate_AddRef(c);
511
0
            bestdc = dc;
512
0
            continue;
513
0
        }
514
        /* policies */
515
        /* XXX later -- defer to policies */
516
0
    }
517
0
    return bestCert;
518
0
}
519
520
NSS_IMPLEMENT PRStatus
521
nssCertificateArray_Traverse(
522
    NSSCertificate **certs,
523
    PRStatus (*callback)(NSSCertificate *c, void *arg),
524
    void *arg)
525
0
{
526
0
    PRStatus status = PR_SUCCESS;
527
0
    if (certs) {
528
0
        NSSCertificate **certp;
529
0
        for (certp = certs; *certp; certp++) {
530
0
            status = (*callback)(*certp, arg);
531
0
            if (status != PR_SUCCESS) {
532
0
                break;
533
0
            }
534
0
        }
535
0
    }
536
0
    return status;
537
0
}
538
539
NSS_IMPLEMENT void
540
nssCRLArray_Destroy(
541
    NSSCRL **crls)
542
0
{
543
0
    if (crls) {
544
0
        NSSCRL **crlp;
545
0
        for (crlp = crls; *crlp; crlp++) {
546
0
            nssCRL_Destroy(*crlp);
547
0
        }
548
0
        nss_ZFreeIf(crls);
549
0
    }
550
0
}
551
552
/*
553
 * Object collections
554
 */
555
556
typedef enum {
557
    pkiObjectType_Certificate = 0,
558
    pkiObjectType_CRL = 1,
559
    pkiObjectType_PrivateKey = 2,
560
    pkiObjectType_PublicKey = 3
561
} pkiObjectType;
562
563
/* Each object is defined by a set of items that uniquely identify it.
564
 * Here are the uid sets:
565
 *
566
 * NSSCertificate ==>  { issuer, serial }
567
 * NSSPrivateKey
568
 *         (RSA) ==> { modulus, public exponent }
569
 *
570
 */
571
0
#define MAX_ITEMS_FOR_UID 2
572
573
/* pkiObjectCollectionNode
574
 *
575
 * A node in the collection is the set of unique identifiers for a single
576
 * object, along with either the actual object or a proto-object.
577
 */
578
typedef struct
579
{
580
    PRCList link;
581
    PRBool haveObject;
582
    nssPKIObject *object;
583
    NSSItem uid[MAX_ITEMS_FOR_UID];
584
} pkiObjectCollectionNode;
585
586
/* nssPKIObjectCollection
587
 *
588
 * The collection is the set of all objects, plus the interfaces needed
589
 * to manage the objects.
590
 *
591
 */
592
struct nssPKIObjectCollectionStr {
593
    NSSArena *arena;
594
    NSSTrustDomain *td;
595
    NSSCryptoContext *cc;
596
    PRCList head; /* list of pkiObjectCollectionNode's */
597
    PRUint32 size;
598
    pkiObjectType objectType;
599
    void (*destroyObject)(nssPKIObject *o);
600
    PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
601
    PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid,
602
                                   NSSArena *arena);
603
    nssPKIObject *(*createObject)(nssPKIObject *o);
604
    nssPKILockType lockType; /* type of lock to use for new proto-objects */
605
};
606
607
static nssPKIObjectCollection *
608
nssPKIObjectCollection_Create(
609
    NSSTrustDomain *td,
610
    NSSCryptoContext *ccOpt,
611
    nssPKILockType lockType)
612
0
{
613
0
    NSSArena *arena;
614
0
    nssPKIObjectCollection *rvCollection = NULL;
615
0
    arena = nssArena_Create();
616
0
    if (!arena) {
617
0
        return (nssPKIObjectCollection *)NULL;
618
0
    }
619
0
    rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
620
0
    if (!rvCollection) {
621
0
        goto loser;
622
0
    }
623
0
    PR_INIT_CLIST(&rvCollection->head);
624
0
    rvCollection->arena = arena;
625
0
    rvCollection->td = td; /* XXX */
626
0
    rvCollection->cc = ccOpt;
627
0
    rvCollection->lockType = lockType;
628
0
    return rvCollection;
629
0
loser:
630
0
    nssArena_Destroy(arena);
631
0
    return (nssPKIObjectCollection *)NULL;
632
0
}
633
634
NSS_IMPLEMENT void
635
nssPKIObjectCollection_Destroy(
636
    nssPKIObjectCollection *collection)
637
0
{
638
0
    if (collection) {
639
0
        PRCList *link;
640
0
        pkiObjectCollectionNode *node;
641
        /* first destroy any objects in the collection */
642
0
        link = PR_NEXT_LINK(&collection->head);
643
0
        while (link != &collection->head) {
644
0
            node = (pkiObjectCollectionNode *)link;
645
0
            if (node->haveObject) {
646
0
                (*collection->destroyObject)(node->object);
647
0
            } else {
648
0
                nssPKIObject_Destroy(node->object);
649
0
            }
650
0
            link = PR_NEXT_LINK(link);
651
0
        }
652
        /* then destroy it */
653
0
        nssArena_Destroy(collection->arena);
654
0
    }
655
0
}
656
657
NSS_IMPLEMENT PRUint32
658
nssPKIObjectCollection_Count(
659
    nssPKIObjectCollection *collection)
660
0
{
661
0
    return collection->size;
662
0
}
663
664
NSS_IMPLEMENT PRStatus
665
nssPKIObjectCollection_AddObject(
666
    nssPKIObjectCollection *collection,
667
    nssPKIObject *object)
668
0
{
669
0
    pkiObjectCollectionNode *node;
670
0
    node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
671
0
    if (!node) {
672
0
        return PR_FAILURE;
673
0
    }
674
0
    node->haveObject = PR_TRUE;
675
0
    node->object = nssPKIObject_AddRef(object);
676
0
    (*collection->getUIDFromObject)(object, node->uid);
677
0
    PR_INIT_CLIST(&node->link);
678
0
    PR_INSERT_BEFORE(&node->link, &collection->head);
679
0
    collection->size++;
680
0
    return PR_SUCCESS;
681
0
}
682
683
static pkiObjectCollectionNode *
684
find_instance_in_collection(
685
    nssPKIObjectCollection *collection,
686
    nssCryptokiObject *instance)
687
0
{
688
0
    PRCList *link;
689
0
    pkiObjectCollectionNode *node;
690
0
    link = PR_NEXT_LINK(&collection->head);
691
0
    while (link != &collection->head) {
692
0
        node = (pkiObjectCollectionNode *)link;
693
0
        if (nssPKIObject_HasInstance(node->object, instance)) {
694
0
            return node;
695
0
        }
696
0
        link = PR_NEXT_LINK(link);
697
0
    }
698
0
    return (pkiObjectCollectionNode *)NULL;
699
0
}
700
701
static pkiObjectCollectionNode *
702
find_object_in_collection(
703
    nssPKIObjectCollection *collection,
704
    NSSItem *uid)
705
0
{
706
0
    PRUint32 i;
707
0
    PRStatus status;
708
0
    PRCList *link;
709
0
    pkiObjectCollectionNode *node;
710
0
    link = PR_NEXT_LINK(&collection->head);
711
0
    while (link != &collection->head) {
712
0
        node = (pkiObjectCollectionNode *)link;
713
0
        for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
714
0
            if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
715
0
                break;
716
0
            }
717
0
        }
718
0
        if (i == MAX_ITEMS_FOR_UID) {
719
0
            return node;
720
0
        }
721
0
        link = PR_NEXT_LINK(link);
722
0
    }
723
0
    return (pkiObjectCollectionNode *)NULL;
724
0
}
725
726
static pkiObjectCollectionNode *
727
add_object_instance(
728
    nssPKIObjectCollection *collection,
729
    nssCryptokiObject *instance,
730
    PRBool *foundIt)
731
0
{
732
0
    PRUint32 i;
733
0
    PRStatus status;
734
0
    pkiObjectCollectionNode *node;
735
0
    nssArenaMark *mark = NULL;
736
0
    NSSItem uid[MAX_ITEMS_FOR_UID];
737
0
    nsslibc_memset(uid, 0, sizeof uid);
738
    /* The list is traversed twice, first (here) looking to match the
739
     * { token, handle } tuple, and if that is not found, below a search
740
     * for unique identifier is done.  Here, a match means this exact object
741
     * instance is already in the collection, and we have nothing to do.
742
     */
743
0
    *foundIt = PR_FALSE;
744
0
    node = find_instance_in_collection(collection, instance);
745
0
    if (node) {
746
        /* The collection is assumed to take over the instance.  Since we
747
         * are not using it, it must be destroyed.
748
         */
749
0
        nssCryptokiObject_Destroy(instance);
750
0
        *foundIt = PR_TRUE;
751
0
        return node;
752
0
    }
753
0
    mark = nssArena_Mark(collection->arena);
754
0
    if (!mark) {
755
0
        goto loser;
756
0
    }
757
0
    status = (*collection->getUIDFromInstance)(instance, uid,
758
0
                                               collection->arena);
759
0
    if (status != PR_SUCCESS) {
760
0
        goto loser;
761
0
    }
762
    /* Search for unique identifier.  A match here means the object exists
763
     * in the collection, but does not have this instance, so the instance
764
     * needs to be added.
765
     */
766
0
    node = find_object_in_collection(collection, uid);
767
0
    if (node) {
768
        /* This is an object with multiple instances */
769
0
        status = nssPKIObject_AddInstance(node->object, instance);
770
0
    } else {
771
        /* This is a completely new object.  Create a node for it. */
772
0
        node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
773
0
        if (!node) {
774
0
            goto loser;
775
0
        }
776
0
        node->object = nssPKIObject_Create(NULL, instance,
777
0
                                           collection->td, collection->cc,
778
0
                                           collection->lockType);
779
0
        if (!node->object) {
780
0
            goto loser;
781
0
        }
782
0
        for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
783
0
            node->uid[i] = uid[i];
784
0
        }
785
0
        node->haveObject = PR_FALSE;
786
0
        PR_INIT_CLIST(&node->link);
787
0
        PR_INSERT_BEFORE(&node->link, &collection->head);
788
0
        collection->size++;
789
0
        status = PR_SUCCESS;
790
0
    }
791
0
    nssArena_Unmark(collection->arena, mark);
792
0
    return node;
793
0
loser:
794
0
    if (mark) {
795
0
        nssArena_Release(collection->arena, mark);
796
0
    }
797
0
    nssCryptokiObject_Destroy(instance);
798
0
    return (pkiObjectCollectionNode *)NULL;
799
0
}
800
801
NSS_IMPLEMENT PRStatus
802
nssPKIObjectCollection_AddInstances(
803
    nssPKIObjectCollection *collection,
804
    nssCryptokiObject **instances,
805
    PRUint32 numInstances)
806
0
{
807
0
    PRStatus status = PR_SUCCESS;
808
0
    PRUint32 i = 0;
809
0
    PRBool foundIt;
810
0
    pkiObjectCollectionNode *node;
811
0
    if (instances) {
812
0
        while ((!numInstances || i < numInstances) && *instances) {
813
0
            if (status == PR_SUCCESS) {
814
0
                node = add_object_instance(collection, *instances, &foundIt);
815
0
                if (node == NULL) {
816
                    /* add_object_instance freed the current instance */
817
                    /* free the remaining instances */
818
0
                    status = PR_FAILURE;
819
0
                }
820
0
            } else {
821
0
                nssCryptokiObject_Destroy(*instances);
822
0
            }
823
0
            instances++;
824
0
            i++;
825
0
        }
826
0
    }
827
0
    return status;
828
0
}
829
830
static void
831
nssPKIObjectCollection_RemoveNode(
832
    nssPKIObjectCollection *collection,
833
    pkiObjectCollectionNode *node)
834
0
{
835
0
    PR_REMOVE_LINK(&node->link);
836
0
    collection->size--;
837
0
}
838
839
static PRStatus
840
nssPKIObjectCollection_GetObjects(
841
    nssPKIObjectCollection *collection,
842
    nssPKIObject **rvObjects,
843
    PRUint32 rvSize)
844
0
{
845
0
    PRUint32 i = 0;
846
0
    PRCList *link = PR_NEXT_LINK(&collection->head);
847
0
    pkiObjectCollectionNode *node;
848
0
    int error = 0;
849
0
    while ((i < rvSize) && (link != &collection->head)) {
850
0
        node = (pkiObjectCollectionNode *)link;
851
0
        if (!node->haveObject) {
852
            /* Convert the proto-object to an object */
853
0
            node->object = (*collection->createObject)(node->object);
854
0
            if (!node->object) {
855
0
                link = PR_NEXT_LINK(link);
856
                /*remove bogus object from list*/
857
0
                nssPKIObjectCollection_RemoveNode(collection, node);
858
0
                error++;
859
0
                continue;
860
0
            }
861
0
            node->haveObject = PR_TRUE;
862
0
        }
863
0
        rvObjects[i++] = nssPKIObject_AddRef(node->object);
864
0
        link = PR_NEXT_LINK(link);
865
0
    }
866
0
    if (!error && *rvObjects == NULL) {
867
0
        nss_SetError(NSS_ERROR_NOT_FOUND);
868
0
    }
869
0
    return PR_SUCCESS;
870
0
}
871
872
NSS_IMPLEMENT PRStatus
873
nssPKIObjectCollection_Traverse(
874
    nssPKIObjectCollection *collection,
875
    nssPKIObjectCallback *callback)
876
0
{
877
0
    PRCList *link = PR_NEXT_LINK(&collection->head);
878
0
    pkiObjectCollectionNode *node;
879
0
    while (link != &collection->head) {
880
0
        node = (pkiObjectCollectionNode *)link;
881
0
        if (!node->haveObject) {
882
0
            node->object = (*collection->createObject)(node->object);
883
0
            if (!node->object) {
884
0
                link = PR_NEXT_LINK(link);
885
                /*remove bogus object from list*/
886
0
                nssPKIObjectCollection_RemoveNode(collection, node);
887
0
                continue;
888
0
            }
889
0
            node->haveObject = PR_TRUE;
890
0
        }
891
0
        switch (collection->objectType) {
892
0
            case pkiObjectType_Certificate:
893
0
                (void)(*callback->func.cert)((NSSCertificate *)node->object,
894
0
                                             callback->arg);
895
0
                break;
896
0
            case pkiObjectType_CRL:
897
0
                (void)(*callback->func.crl)((NSSCRL *)node->object,
898
0
                                            callback->arg);
899
0
                break;
900
0
            case pkiObjectType_PrivateKey:
901
0
                (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object,
902
0
                                              callback->arg);
903
0
                break;
904
0
            case pkiObjectType_PublicKey:
905
0
                (void)(*callback->func.pbkey)((NSSPublicKey *)node->object,
906
0
                                              callback->arg);
907
0
                break;
908
0
        }
909
0
        link = PR_NEXT_LINK(link);
910
0
    }
911
0
    return PR_SUCCESS;
912
0
}
913
914
NSS_IMPLEMENT PRStatus
915
nssPKIObjectCollection_AddInstanceAsObject(
916
    nssPKIObjectCollection *collection,
917
    nssCryptokiObject *instance)
918
0
{
919
0
    pkiObjectCollectionNode *node;
920
0
    PRBool foundIt;
921
0
    node = add_object_instance(collection, instance, &foundIt);
922
0
    if (node == NULL) {
923
0
        return PR_FAILURE;
924
0
    }
925
0
    if (!node->haveObject) {
926
0
        nssPKIObject *original = node->object;
927
0
        node->object = (*collection->createObject)(node->object);
928
0
        if (!node->object) {
929
            /*remove bogus object from list*/
930
0
            nssPKIObject_Destroy(original);
931
0
            nssPKIObjectCollection_RemoveNode(collection, node);
932
0
            return PR_FAILURE;
933
0
        }
934
0
        node->haveObject = PR_TRUE;
935
0
    } else if (!foundIt) {
936
        /* The instance was added to a pre-existing node.  This
937
         * function is *only* being used for certificates, and having
938
         * multiple instances of certs in 3.X requires updating the
939
         * CERTCertificate.
940
         * But only do it if it was a new instance!!!  If the same instance
941
         * is encountered, we set *foundIt to true.  Detect that here and
942
         * ignore it.
943
         */
944
0
        STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
945
0
    }
946
0
    return PR_SUCCESS;
947
0
}
948
949
/*
950
 * Certificate collections
951
 */
952
953
static void
954
cert_destroyObject(nssPKIObject *o)
955
0
{
956
0
    NSSCertificate *c = (NSSCertificate *)o;
957
0
    if (c->decoding) {
958
0
        CERTCertificate *cc = STAN_GetCERTCertificate(c);
959
0
        if (cc) {
960
0
            CERT_DestroyCertificate(cc);
961
0
            return;
962
0
        } /* else destroy it as NSSCertificate below */
963
0
    }
964
0
    nssCertificate_Destroy(c);
965
0
}
966
967
static PRStatus
968
cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
969
0
{
970
0
    NSSCertificate *c = (NSSCertificate *)o;
971
    /* The builtins are still returning decoded serial numbers.  Until
972
     * this compatibility issue is resolved, use the full DER of the
973
     * cert to uniquely identify it.
974
     */
975
0
    NSSDER *derCert;
976
0
    derCert = nssCertificate_GetEncoding(c);
977
0
    uid[0].data = NULL;
978
0
    uid[0].size = 0;
979
0
    uid[1].data = NULL;
980
0
    uid[1].size = 0;
981
0
    if (derCert != NULL) {
982
0
        uid[0] = *derCert;
983
0
    }
984
0
    return PR_SUCCESS;
985
0
}
986
987
static PRStatus
988
cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
989
                        NSSArena *arena)
990
0
{
991
    /* The builtins are still returning decoded serial numbers.  Until
992
     * this compatibility issue is resolved, use the full DER of the
993
     * cert to uniquely identify it.
994
     */
995
0
    uid[1].data = NULL;
996
0
    uid[1].size = 0;
997
0
    return nssCryptokiCertificate_GetAttributes(instance,
998
0
                                                NULL,    /* XXX sessionOpt */
999
0
                                                arena,   /* arena    */
1000
0
                                                NULL,    /* type     */
1001
0
                                                NULL,    /* id       */
1002
0
                                                &uid[0], /* encoding */
1003
0
                                                NULL,    /* issuer   */
1004
0
                                                NULL,    /* serial   */
1005
0
                                                NULL);   /* subject  */
1006
0
}
1007
1008
static nssPKIObject *
1009
cert_createObject(nssPKIObject *o)
1010
0
{
1011
0
    NSSCertificate *cert;
1012
0
    cert = nssCertificate_Create(o);
1013
    /*    if (STAN_GetCERTCertificate(cert) == NULL) {
1014
        nssCertificate_Destroy(cert);
1015
        return (nssPKIObject *)NULL;
1016
    } */
1017
    /* In 3.4, have to maintain uniqueness of cert pointers by caching all
1018
     * certs.  Cache the cert here, before returning.  If it is already
1019
     * cached, take the cached entry.
1020
     */
1021
0
    {
1022
0
        NSSTrustDomain *td = o->trustDomain;
1023
0
        nssTrustDomain_AddCertsToCache(td, &cert, 1);
1024
0
    }
1025
0
    return (nssPKIObject *)cert;
1026
0
}
1027
1028
NSS_IMPLEMENT nssPKIObjectCollection *
1029
nssCertificateCollection_Create(
1030
    NSSTrustDomain *td,
1031
    NSSCertificate **certsOpt)
1032
0
{
1033
0
    nssPKIObjectCollection *collection;
1034
0
    collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
1035
0
    if (!collection) {
1036
0
        return NULL;
1037
0
    }
1038
0
    collection->objectType = pkiObjectType_Certificate;
1039
0
    collection->destroyObject = cert_destroyObject;
1040
0
    collection->getUIDFromObject = cert_getUIDFromObject;
1041
0
    collection->getUIDFromInstance = cert_getUIDFromInstance;
1042
0
    collection->createObject = cert_createObject;
1043
0
    if (certsOpt) {
1044
0
        for (; *certsOpt; certsOpt++) {
1045
0
            nssPKIObject *object = (nssPKIObject *)(*certsOpt);
1046
0
            (void)nssPKIObjectCollection_AddObject(collection, object);
1047
0
        }
1048
0
    }
1049
0
    return collection;
1050
0
}
1051
1052
NSS_IMPLEMENT NSSCertificate **
1053
nssPKIObjectCollection_GetCertificates(
1054
    nssPKIObjectCollection *collection,
1055
    NSSCertificate **rvOpt,
1056
    PRUint32 maximumOpt,
1057
    NSSArena *arenaOpt)
1058
0
{
1059
0
    PRStatus status;
1060
0
    PRUint32 rvSize;
1061
0
    PRBool allocated = PR_FALSE;
1062
0
    if (collection->size == 0) {
1063
0
        return (NSSCertificate **)NULL;
1064
0
    }
1065
0
    if (maximumOpt == 0) {
1066
0
        rvSize = collection->size;
1067
0
    } else {
1068
0
        rvSize = PR_MIN(collection->size, maximumOpt);
1069
0
    }
1070
0
    if (!rvOpt) {
1071
0
        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
1072
0
        if (!rvOpt) {
1073
0
            return (NSSCertificate **)NULL;
1074
0
        }
1075
0
        allocated = PR_TRUE;
1076
0
    }
1077
0
    status = nssPKIObjectCollection_GetObjects(collection,
1078
0
                                               (nssPKIObject **)rvOpt,
1079
0
                                               rvSize);
1080
0
    if (status != PR_SUCCESS) {
1081
0
        if (allocated) {
1082
0
            nss_ZFreeIf(rvOpt);
1083
0
        }
1084
0
        return (NSSCertificate **)NULL;
1085
0
    }
1086
0
    return rvOpt;
1087
0
}
1088
1089
/*
1090
 * CRL/KRL collections
1091
 */
1092
1093
static void
1094
crl_destroyObject(nssPKIObject *o)
1095
0
{
1096
0
    NSSCRL *crl = (NSSCRL *)o;
1097
0
    nssCRL_Destroy(crl);
1098
0
}
1099
1100
static PRStatus
1101
crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
1102
0
{
1103
0
    NSSCRL *crl = (NSSCRL *)o;
1104
0
    NSSDER *encoding;
1105
0
    encoding = nssCRL_GetEncoding(crl);
1106
0
    if (!encoding) {
1107
0
        nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
1108
0
        return PR_FALSE;
1109
0
    }
1110
0
    uid[0] = *encoding;
1111
0
    uid[1].data = NULL;
1112
0
    uid[1].size = 0;
1113
0
    return PR_SUCCESS;
1114
0
}
1115
1116
static PRStatus
1117
crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
1118
                       NSSArena *arena)
1119
0
{
1120
0
    return nssCryptokiCRL_GetAttributes(instance,
1121
0
                                        NULL,    /* XXX sessionOpt */
1122
0
                                        arena,   /* arena    */
1123
0
                                        &uid[0], /* encoding */
1124
0
                                        NULL,    /* subject  */
1125
0
                                        NULL,    /* class    */
1126
0
                                        NULL,    /* url      */
1127
0
                                        NULL);   /* isKRL    */
1128
0
}
1129
1130
static nssPKIObject *
1131
crl_createObject(nssPKIObject *o)
1132
0
{
1133
0
    return (nssPKIObject *)nssCRL_Create(o);
1134
0
}
1135
1136
NSS_IMPLEMENT nssPKIObjectCollection *
1137
nssCRLCollection_Create(
1138
    NSSTrustDomain *td,
1139
    NSSCRL **crlsOpt)
1140
0
{
1141
0
    nssPKIObjectCollection *collection;
1142
0
    collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
1143
0
    if (!collection) {
1144
0
        return NULL;
1145
0
    }
1146
0
    collection->objectType = pkiObjectType_CRL;
1147
0
    collection->destroyObject = crl_destroyObject;
1148
0
    collection->getUIDFromObject = crl_getUIDFromObject;
1149
0
    collection->getUIDFromInstance = crl_getUIDFromInstance;
1150
0
    collection->createObject = crl_createObject;
1151
0
    if (crlsOpt) {
1152
0
        for (; *crlsOpt; crlsOpt++) {
1153
0
            nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
1154
0
            (void)nssPKIObjectCollection_AddObject(collection, object);
1155
0
        }
1156
0
    }
1157
0
    return collection;
1158
0
}
1159
1160
NSS_IMPLEMENT NSSCRL **
1161
nssPKIObjectCollection_GetCRLs(
1162
    nssPKIObjectCollection *collection,
1163
    NSSCRL **rvOpt,
1164
    PRUint32 maximumOpt,
1165
    NSSArena *arenaOpt)
1166
0
{
1167
0
    PRStatus status;
1168
0
    PRUint32 rvSize;
1169
0
    PRBool allocated = PR_FALSE;
1170
0
    if (collection->size == 0) {
1171
0
        return (NSSCRL **)NULL;
1172
0
    }
1173
0
    if (maximumOpt == 0) {
1174
0
        rvSize = collection->size;
1175
0
    } else {
1176
0
        rvSize = PR_MIN(collection->size, maximumOpt);
1177
0
    }
1178
0
    if (!rvOpt) {
1179
0
        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
1180
0
        if (!rvOpt) {
1181
0
            return (NSSCRL **)NULL;
1182
0
        }
1183
0
        allocated = PR_TRUE;
1184
0
    }
1185
0
    status = nssPKIObjectCollection_GetObjects(collection,
1186
0
                                               (nssPKIObject **)rvOpt,
1187
0
                                               rvSize);
1188
0
    if (status != PR_SUCCESS) {
1189
0
        if (allocated) {
1190
0
            nss_ZFreeIf(rvOpt);
1191
0
        }
1192
0
        return (NSSCRL **)NULL;
1193
0
    }
1194
0
    return rvOpt;
1195
0
}
1196
1197
/* how bad would it be to have a static now sitting around, updated whenever
1198
 * this was called?  would avoid repeated allocs...
1199
 */
1200
NSS_IMPLEMENT NSSTime *
1201
NSSTime_Now(NSSTime *timeOpt)
1202
0
{
1203
0
    return NSSTime_SetPRTime(timeOpt, PR_Now());
1204
0
}
1205
1206
NSS_IMPLEMENT NSSTime *
1207
NSSTime_SetPRTime(
1208
    NSSTime *timeOpt,
1209
    PRTime prTime)
1210
0
{
1211
0
    NSSTime *rvTime;
1212
0
    rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
1213
0
    if (rvTime) {
1214
0
        rvTime->prTime = prTime;
1215
0
    }
1216
0
    return rvTime;
1217
0
}
1218
1219
NSS_IMPLEMENT PRTime
1220
NSSTime_GetPRTime(
1221
    NSSTime *time)
1222
0
{
1223
0
    return time->prTime;
1224
0
}