Coverage Report

Created: 2024-05-20 06:23

/src/nss/lib/certhigh/certhigh.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
#include "nspr.h"
5
#include "secerr.h"
6
#include "secasn1.h"
7
#include "seccomon.h"
8
#include "pk11func.h"
9
#include "certdb.h"
10
#include "certt.h"
11
#include "cert.h"
12
#include "certxutl.h"
13
14
#include "certi.h"
15
#include "nsspki.h"
16
#include "pki.h"
17
#include "pkit.h"
18
#include "pkitm.h"
19
#include "pki3hack.h"
20
21
PRBool
22
CERT_MatchNickname(char *name1, char *name2)
23
0
{
24
0
    char *nickname1 = NULL;
25
0
    char *nickname2 = NULL;
26
0
    char *token1;
27
0
    char *token2;
28
29
    /* first deal with the straight comparison */
30
0
    if (PORT_Strcmp(name1, name2) == 0) {
31
0
        return PR_TRUE;
32
0
    }
33
    /* we need to handle the case where one name has an explicit token and the other
34
     * doesn't */
35
0
    token1 = PORT_Strchr(name1, ':');
36
0
    token2 = PORT_Strchr(name2, ':');
37
0
    if ((token1 && token2) || (!token1 && !token2)) {
38
        /* either both token names are specified or neither are, not match */
39
0
        return PR_FALSE;
40
0
    }
41
0
    if (token1) {
42
0
        nickname1 = token1;
43
0
        nickname2 = name2;
44
0
    } else {
45
0
        nickname1 = token2;
46
0
        nickname2 = name1;
47
0
    }
48
0
    nickname1++;
49
0
    if (PORT_Strcmp(nickname1, nickname2) != 0) {
50
0
        return PR_FALSE;
51
0
    }
52
    /* Bug 1192443 - compare the other token with the internal slot here */
53
0
    return PR_TRUE;
54
0
}
55
56
/*
57
 * Find all user certificates that match the given criteria.
58
 *
59
 *      "handle" - database to search
60
 *      "usage" - certificate usage to match
61
 *      "oneCertPerName" - if set then only return the "best" cert per
62
 *                      name
63
 *      "validOnly" - only return certs that are curently valid
64
 *      "proto_win" - window handle passed to pkcs11
65
 */
66
CERTCertList *
67
CERT_FindUserCertsByUsage(CERTCertDBHandle *handle,
68
                          SECCertUsage usage,
69
                          PRBool oneCertPerName,
70
                          PRBool validOnly,
71
                          void *proto_win)
72
0
{
73
0
    CERTCertNicknames *nicknames = NULL;
74
0
    char **nnptr;
75
0
    int nn;
76
0
    CERTCertificate *cert = NULL;
77
0
    CERTCertList *certList = NULL;
78
0
    SECStatus rv;
79
0
    PRTime time;
80
0
    CERTCertListNode *node = NULL;
81
0
    CERTCertListNode *freenode = NULL;
82
0
    int n;
83
84
0
    time = PR_Now();
85
86
0
    nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER,
87
0
                                      proto_win);
88
89
0
    if ((nicknames == NULL) || (nicknames->numnicknames == 0)) {
90
0
        goto loser;
91
0
    }
92
93
0
    nnptr = nicknames->nicknames;
94
0
    nn = nicknames->numnicknames;
95
96
0
    while (nn > 0) {
97
0
        cert = NULL;
98
        /* use the pk11 call so that we pick up any certs on tokens,
99
         * which may require login
100
         */
101
0
        if (proto_win != NULL) {
102
0
            cert = PK11_FindCertFromNickname(*nnptr, proto_win);
103
0
        }
104
105
        /* Sigh, It turns out if the cert is already in the temp db, because
106
         * it's in the perm db, then the nickname lookup doesn't work.
107
         * since we already have the cert here, though, than we can just call
108
         * CERT_CreateSubjectCertList directly. For those cases where we didn't
109
         * find the cert in pkcs #11 (because we didn't have a password arg,
110
         * or because the nickname is for a peer, server, or CA cert, then we
111
         * go look the cert up.
112
         */
113
0
        if (cert == NULL) {
114
0
            cert = CERT_FindCertByNickname(handle, *nnptr);
115
0
        }
116
117
0
        if (cert != NULL) {
118
            /* collect certs for this nickname, sorting them into the list */
119
0
            certList = CERT_CreateSubjectCertList(certList, handle,
120
0
                                                  &cert->derSubject, time, validOnly);
121
122
0
            CERT_FilterCertListForUserCerts(certList);
123
124
            /* drop the extra reference */
125
0
            CERT_DestroyCertificate(cert);
126
0
        }
127
128
0
        nnptr++;
129
0
        nn--;
130
0
    }
131
132
    /* remove certs with incorrect usage */
133
0
    rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
134
135
0
    if (rv != SECSuccess) {
136
0
        goto loser;
137
0
    }
138
139
    /* remove any extra certs for each name */
140
0
    if (oneCertPerName) {
141
0
        PRBool *flags;
142
143
0
        nn = nicknames->numnicknames;
144
0
        nnptr = nicknames->nicknames;
145
146
0
        if (!certList) {
147
0
            goto loser;
148
0
        }
149
150
0
        flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn);
151
0
        if (flags == NULL) {
152
0
            goto loser;
153
0
        }
154
155
0
        node = CERT_LIST_HEAD(certList);
156
157
        /* treverse all certs in the list */
158
0
        while (!CERT_LIST_END(node, certList)) {
159
160
            /* find matching nickname index */
161
0
            for (n = 0; n < nn; n++) {
162
0
                if (CERT_MatchNickname(nnptr[n], node->cert->nickname)) {
163
                    /* We found a match.  If this is the first one, then
164
                     * set the flag and move on to the next cert.  If this
165
                     * is not the first one then delete it from the list.
166
                     */
167
0
                    if (flags[n]) {
168
                        /* We have already seen a cert with this nickname,
169
                         * so delete this one.
170
                         */
171
0
                        freenode = node;
172
0
                        node = CERT_LIST_NEXT(node);
173
0
                        CERT_RemoveCertListNode(freenode);
174
0
                    } else {
175
                        /* keep the first cert for each nickname, but set the
176
                         * flag so we know to delete any others with the same
177
                         * nickname.
178
                         */
179
0
                        flags[n] = PR_TRUE;
180
0
                        node = CERT_LIST_NEXT(node);
181
0
                    }
182
0
                    break;
183
0
                }
184
0
            }
185
0
            if (n == nn) {
186
                /* if we get here it means that we didn't find a matching
187
                 * nickname, which should not happen.
188
                 */
189
0
                PORT_Assert(0);
190
0
                node = CERT_LIST_NEXT(node);
191
0
            }
192
0
        }
193
0
        PORT_Free(flags);
194
0
    }
195
196
0
    goto done;
197
198
0
loser:
199
0
    if (certList != NULL) {
200
0
        CERT_DestroyCertList(certList);
201
0
        certList = NULL;
202
0
    }
203
204
0
done:
205
0
    if (nicknames != NULL) {
206
0
        CERT_FreeNicknames(nicknames);
207
0
    }
208
209
0
    return (certList);
210
0
}
211
212
/*
213
 * Find a user certificate that matchs the given criteria.
214
 *
215
 *      "handle" - database to search
216
 *      "nickname" - nickname to match
217
 *      "usage" - certificate usage to match
218
 *      "validOnly" - only return certs that are curently valid
219
 *      "proto_win" - window handle passed to pkcs11
220
 */
221
CERTCertificate *
222
CERT_FindUserCertByUsage(CERTCertDBHandle *handle,
223
                         const char *nickname,
224
                         SECCertUsage usage,
225
                         PRBool validOnly,
226
                         void *proto_win)
227
0
{
228
0
    CERTCertificate *cert = NULL;
229
0
    CERTCertList *certList = NULL;
230
0
    SECStatus rv;
231
0
    PRTime time;
232
233
0
    time = PR_Now();
234
235
    /* use the pk11 call so that we pick up any certs on tokens,
236
     * which may require login
237
     */
238
    /* XXX - why is this restricted? */
239
0
    if (proto_win != NULL) {
240
0
        cert = PK11_FindCertFromNickname(nickname, proto_win);
241
0
    }
242
243
    /* sigh, There are still problems find smart cards from the temp
244
     * db. This will get smart cards working again. The real fix
245
     * is to make sure we can search the temp db by their token nickname.
246
     */
247
0
    if (cert == NULL) {
248
0
        cert = CERT_FindCertByNickname(handle, nickname);
249
0
    }
250
251
0
    if (cert != NULL) {
252
0
        unsigned int requiredKeyUsage;
253
0
        unsigned int requiredCertType;
254
255
0
        rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE,
256
0
                                              &requiredKeyUsage, &requiredCertType);
257
0
        if (rv != SECSuccess) {
258
            /* drop the extra reference */
259
0
            CERT_DestroyCertificate(cert);
260
0
            cert = NULL;
261
0
            goto loser;
262
0
        }
263
        /* If we already found the right cert, just return it */
264
0
        if ((!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE) == secCertTimeValid) &&
265
0
            (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) &&
266
0
            (cert->nsCertType & requiredCertType) &&
267
0
            CERT_IsUserCert(cert)) {
268
0
            return (cert);
269
0
        }
270
271
        /* collect certs for this nickname, sorting them into the list */
272
0
        certList = CERT_CreateSubjectCertList(certList, handle,
273
0
                                              &cert->derSubject, time, validOnly);
274
275
0
        CERT_FilterCertListForUserCerts(certList);
276
277
        /* drop the extra reference */
278
0
        CERT_DestroyCertificate(cert);
279
0
        cert = NULL;
280
0
    }
281
282
0
    if (certList == NULL) {
283
0
        goto loser;
284
0
    }
285
286
    /* remove certs with incorrect usage */
287
0
    rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
288
289
0
    if (rv != SECSuccess) {
290
0
        goto loser;
291
0
    }
292
293
0
    if (!CERT_LIST_EMPTY(certList)) {
294
0
        cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
295
0
    }
296
297
0
loser:
298
0
    if (certList != NULL) {
299
0
        CERT_DestroyCertList(certList);
300
0
    }
301
302
0
    return (cert);
303
0
}
304
305
CERTCertList *
306
CERT_MatchUserCert(CERTCertDBHandle *handle,
307
                   SECCertUsage usage,
308
                   int nCANames, char **caNames,
309
                   void *proto_win)
310
0
{
311
0
    CERTCertList *certList = NULL;
312
0
    SECStatus rv;
313
314
0
    certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE,
315
0
                                         proto_win);
316
0
    if (certList == NULL) {
317
0
        goto loser;
318
0
    }
319
320
0
    rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage);
321
0
    if (rv != SECSuccess) {
322
0
        goto loser;
323
0
    }
324
325
0
    goto done;
326
327
0
loser:
328
0
    if (certList != NULL) {
329
0
        CERT_DestroyCertList(certList);
330
0
        certList = NULL;
331
0
    }
332
333
0
done:
334
335
0
    return (certList);
336
0
}
337
338
typedef struct stringNode {
339
    struct stringNode *next;
340
    char *string;
341
} stringNode;
342
343
static PRStatus
344
CollectNicknames(NSSCertificate *c, void *data)
345
0
{
346
0
    CERTCertNicknames *names;
347
0
    PRBool saveit = PR_FALSE;
348
0
    stringNode *node;
349
0
    int len;
350
#ifdef notdef
351
    NSSTrustDomain *td;
352
    NSSTrust *trust;
353
#endif
354
0
    char *stanNickname;
355
0
    char *nickname = NULL;
356
357
0
    names = (CERTCertNicknames *)data;
358
359
0
    stanNickname = nssCertificate_GetNickname(c, NULL);
360
361
0
    if (stanNickname) {
362
0
        nss_ZFreeIf(stanNickname);
363
0
        stanNickname = NULL;
364
0
        if (names->what == SEC_CERT_NICKNAMES_USER) {
365
0
            saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL);
366
0
        }
367
#ifdef notdef
368
        else {
369
            td = NSSCertificate_GetTrustDomain(c);
370
            if (!td) {
371
                return PR_SUCCESS;
372
            }
373
            trust = nssTrustDomain_FindTrustForCertificate(td, c);
374
375
            switch (names->what) {
376
                case SEC_CERT_NICKNAMES_ALL:
377
                    if ((trust->sslFlags & (CERTDB_VALID_CA | CERTDB_VALID_PEER)) ||
378
                        (trust->emailFlags & (CERTDB_VALID_CA | CERTDB_VALID_PEER)) ||
379
                        (trust->objectSigningFlags &
380
                         (CERTDB_VALID_CA | CERTDB_VALID_PEER))) {
381
                        saveit = PR_TRUE;
382
                    }
383
384
                    break;
385
                case SEC_CERT_NICKNAMES_SERVER:
386
                    if (trust->sslFlags & CERTDB_VALID_PEER) {
387
                        saveit = PR_TRUE;
388
                    }
389
390
                    break;
391
                case SEC_CERT_NICKNAMES_CA:
392
                    if (((trust->sslFlags & CERTDB_VALID_CA) == CERTDB_VALID_CA) ||
393
                        ((trust->emailFlags & CERTDB_VALID_CA) == CERTDB_VALID_CA) ||
394
                        ((trust->objectSigningFlags & CERTDB_VALID_CA) ==
395
                         CERTDB_VALID_CA)) {
396
                        saveit = PR_TRUE;
397
                    }
398
                    break;
399
            }
400
        }
401
#endif
402
0
    }
403
404
    /* traverse the list of collected nicknames and make sure we don't make
405
     * a duplicate
406
     */
407
0
    if (saveit) {
408
0
        nickname = STAN_GetCERTCertificateName(NULL, c);
409
        /* nickname can only be NULL here if we are having memory
410
         * alloc problems */
411
0
        if (nickname == NULL) {
412
0
            return PR_FAILURE;
413
0
        }
414
0
        node = (stringNode *)names->head;
415
0
        while (node != NULL) {
416
0
            if (PORT_Strcmp(nickname, node->string) == 0) {
417
                /* if the string matches, then don't save this one */
418
0
                saveit = PR_FALSE;
419
0
                break;
420
0
            }
421
0
            node = node->next;
422
0
        }
423
0
    }
424
425
0
    if (saveit) {
426
427
        /* allocate the node */
428
0
        node = (stringNode *)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
429
0
        if (node == NULL) {
430
0
            PORT_Free(nickname);
431
0
            return PR_FAILURE;
432
0
        }
433
434
        /* copy the string */
435
0
        len = PORT_Strlen(nickname) + 1;
436
0
        node->string = (char *)PORT_ArenaAlloc(names->arena, len);
437
0
        if (node->string == NULL) {
438
0
            PORT_Free(nickname);
439
0
            return PR_FAILURE;
440
0
        }
441
0
        PORT_Memcpy(node->string, nickname, len);
442
443
        /* link it into the list */
444
0
        node->next = (stringNode *)names->head;
445
0
        names->head = (void *)node;
446
447
        /* bump the count */
448
0
        names->numnicknames++;
449
0
    }
450
451
0
    if (nickname)
452
0
        PORT_Free(nickname);
453
0
    return (PR_SUCCESS);
454
0
}
455
456
CERTCertNicknames *
457
CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
458
0
{
459
0
    PLArenaPool *arena;
460
0
    CERTCertNicknames *names;
461
0
    int i;
462
0
    stringNode *node;
463
464
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
465
0
    if (arena == NULL) {
466
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
467
0
        return (NULL);
468
0
    }
469
470
0
    names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
471
0
    if (names == NULL) {
472
0
        goto loser;
473
0
    }
474
475
0
    names->arena = arena;
476
0
    names->head = NULL;
477
0
    names->numnicknames = 0;
478
0
    names->nicknames = NULL;
479
0
    names->what = what;
480
0
    names->totallen = 0;
481
482
    /* make sure we are logged in */
483
0
    (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
484
485
0
    NSSTrustDomain_TraverseCertificates(handle,
486
0
                                        CollectNicknames, (void *)names);
487
0
    if (names->numnicknames) {
488
0
        names->nicknames = (char **)PORT_ArenaAlloc(arena,
489
0
                                                    names->numnicknames *
490
0
                                                        sizeof(char *));
491
492
0
        if (names->nicknames == NULL) {
493
0
            goto loser;
494
0
        }
495
496
0
        node = (stringNode *)names->head;
497
498
0
        for (i = 0; i < names->numnicknames; i++) {
499
0
            PORT_Assert(node != NULL);
500
501
0
            names->nicknames[i] = node->string;
502
0
            names->totallen += PORT_Strlen(node->string);
503
0
            node = node->next;
504
0
        }
505
506
0
        PORT_Assert(node == NULL);
507
0
    }
508
509
0
    return (names);
510
511
0
loser:
512
0
    PORT_FreeArena(arena, PR_FALSE);
513
0
    return (NULL);
514
0
}
515
516
void
517
CERT_FreeNicknames(CERTCertNicknames *nicknames)
518
0
{
519
0
    PORT_FreeArena(nicknames->arena, PR_FALSE);
520
521
0
    return;
522
0
}
523
524
/* [ FROM pcertdb.c ] */
525
526
typedef struct dnameNode {
527
    struct dnameNode *next;
528
    SECItem name;
529
} dnameNode;
530
531
void
532
CERT_FreeDistNames(CERTDistNames *names)
533
4
{
534
4
    PORT_FreeArena(names->arena, PR_FALSE);
535
536
4
    return;
537
4
}
538
539
static SECStatus
540
CollectDistNames(CERTCertificate *cert, SECItem *k, void *data)
541
0
{
542
0
    CERTDistNames *names;
543
0
    PRBool saveit = PR_FALSE;
544
0
    CERTCertTrust trust;
545
0
    dnameNode *node;
546
0
    int len;
547
548
0
    names = (CERTDistNames *)data;
549
550
0
    if (CERT_GetCertTrust(cert, &trust) == SECSuccess) {
551
        /* only collect names of CAs trusted for issuing SSL clients */
552
0
        if (trust.sslFlags & CERTDB_TRUSTED_CLIENT_CA) {
553
0
            saveit = PR_TRUE;
554
0
        }
555
0
    }
556
557
0
    if (saveit) {
558
        /* allocate the node */
559
0
        node = (dnameNode *)PORT_ArenaAlloc(names->arena, sizeof(dnameNode));
560
0
        if (node == NULL) {
561
0
            return (SECFailure);
562
0
        }
563
564
        /* copy the name */
565
0
        node->name.len = len = cert->derSubject.len;
566
0
        node->name.type = siBuffer;
567
0
        node->name.data = (unsigned char *)PORT_ArenaAlloc(names->arena, len);
568
0
        if (node->name.data == NULL) {
569
0
            return (SECFailure);
570
0
        }
571
0
        PORT_Memcpy(node->name.data, cert->derSubject.data, len);
572
573
        /* link it into the list */
574
0
        node->next = (dnameNode *)names->head;
575
0
        names->head = (void *)node;
576
577
        /* bump the count */
578
0
        names->nnames++;
579
0
    }
580
581
0
    return (SECSuccess);
582
0
}
583
584
/*
585
 * Return all of the CAs that are "trusted" for SSL.
586
 */
587
CERTDistNames *
588
CERT_DupDistNames(CERTDistNames *orig)
589
0
{
590
0
    PLArenaPool *arena;
591
0
    CERTDistNames *names;
592
0
    int i;
593
0
    SECStatus rv;
594
595
    /* allocate an arena to use */
596
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
597
0
    if (arena == NULL) {
598
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
599
0
        return (NULL);
600
0
    }
601
602
    /* allocate the header structure */
603
0
    names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
604
0
    if (names == NULL) {
605
0
        goto loser;
606
0
    }
607
608
    /* initialize the header struct */
609
0
    names->arena = arena;
610
0
    names->head = NULL;
611
0
    names->nnames = orig->nnames;
612
0
    names->names = NULL;
613
614
    /* construct the array from the list */
615
0
    if (orig->nnames) {
616
0
        names->names = (SECItem *)PORT_ArenaNewArray(arena, SECItem,
617
0
                                                     orig->nnames);
618
0
        if (names->names == NULL) {
619
0
            goto loser;
620
0
        }
621
0
        for (i = 0; i < orig->nnames; i++) {
622
0
            rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]);
623
0
            if (rv != SECSuccess) {
624
0
                goto loser;
625
0
            }
626
0
        }
627
0
    }
628
0
    return (names);
629
630
0
loser:
631
0
    PORT_FreeArena(arena, PR_FALSE);
632
0
    return (NULL);
633
0
}
634
635
CERTDistNames *
636
CERT_GetSSLCACerts(CERTCertDBHandle *handle)
637
4
{
638
4
    PLArenaPool *arena;
639
4
    CERTDistNames *names;
640
4
    int i;
641
4
    SECStatus rv;
642
4
    dnameNode *node;
643
644
    /* allocate an arena to use */
645
4
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
646
4
    if (arena == NULL) {
647
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
648
0
        return (NULL);
649
0
    }
650
651
    /* allocate the header structure */
652
4
    names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
653
4
    if (names == NULL) {
654
0
        goto loser;
655
0
    }
656
657
    /* initialize the header struct */
658
4
    names->arena = arena;
659
4
    names->head = NULL;
660
4
    names->nnames = 0;
661
4
    names->names = NULL;
662
663
    /* collect the names from the database */
664
4
    rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL);
665
4
    if (rv) {
666
0
        goto loser;
667
0
    }
668
669
    /* construct the array from the list */
670
4
    if (names->nnames) {
671
0
        names->names = (SECItem *)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem));
672
673
0
        if (names->names == NULL) {
674
0
            goto loser;
675
0
        }
676
677
0
        node = (dnameNode *)names->head;
678
679
0
        for (i = 0; i < names->nnames; i++) {
680
0
            PORT_Assert(node != NULL);
681
682
0
            names->names[i] = node->name;
683
0
            node = node->next;
684
0
        }
685
686
0
        PORT_Assert(node == NULL);
687
0
    }
688
689
4
    return (names);
690
691
0
loser:
692
0
    PORT_FreeArena(arena, PR_FALSE);
693
0
    return (NULL);
694
4
}
695
696
CERTDistNames *
697
CERT_DistNamesFromCertList(CERTCertList *certList)
698
0
{
699
0
    CERTDistNames *dnames = NULL;
700
0
    PLArenaPool *arena;
701
0
    CERTCertListNode *node = NULL;
702
0
    SECItem *names = NULL;
703
0
    int listLen = 0, i = 0;
704
705
0
    if (certList == NULL) {
706
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
707
0
        return NULL;
708
0
    }
709
710
0
    node = CERT_LIST_HEAD(certList);
711
0
    while (!CERT_LIST_END(node, certList)) {
712
0
        listLen += 1;
713
0
        node = CERT_LIST_NEXT(node);
714
0
    }
715
716
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
717
0
    if (arena == NULL)
718
0
        goto loser;
719
0
    dnames = PORT_ArenaZNew(arena, CERTDistNames);
720
0
    if (dnames == NULL)
721
0
        goto loser;
722
723
0
    dnames->arena = arena;
724
0
    dnames->nnames = listLen;
725
0
    dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen);
726
0
    if (names == NULL)
727
0
        goto loser;
728
729
0
    node = CERT_LIST_HEAD(certList);
730
0
    while (!CERT_LIST_END(node, certList)) {
731
0
        CERTCertificate *cert = node->cert;
732
0
        SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject);
733
0
        if (rv == SECFailure) {
734
0
            goto loser;
735
0
        }
736
0
        node = CERT_LIST_NEXT(node);
737
0
    }
738
0
    return dnames;
739
0
loser:
740
0
    if (arena) {
741
0
        PORT_FreeArena(arena, PR_FALSE);
742
0
    }
743
0
    return NULL;
744
0
}
745
746
CERTDistNames *
747
CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
748
                            int nnames)
749
0
{
750
0
    CERTDistNames *dnames = NULL;
751
0
    PLArenaPool *arena;
752
0
    int i, rv;
753
0
    SECItem *names = NULL;
754
0
    CERTCertificate *cert = NULL;
755
756
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
757
0
    if (arena == NULL)
758
0
        goto loser;
759
0
    dnames = PORT_ArenaZNew(arena, CERTDistNames);
760
0
    if (dnames == NULL)
761
0
        goto loser;
762
763
0
    dnames->arena = arena;
764
0
    dnames->nnames = nnames;
765
0
    dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
766
0
    if (names == NULL)
767
0
        goto loser;
768
769
0
    for (i = 0; i < nnames; i++) {
770
0
        cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]);
771
0
        if (cert == NULL)
772
0
            goto loser;
773
0
        rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject);
774
0
        if (rv == SECFailure)
775
0
            goto loser;
776
0
        CERT_DestroyCertificate(cert);
777
0
    }
778
0
    return dnames;
779
780
0
loser:
781
0
    if (cert != NULL)
782
0
        CERT_DestroyCertificate(cert);
783
0
    if (arena != NULL)
784
0
        PORT_FreeArena(arena, PR_FALSE);
785
0
    return NULL;
786
0
}
787
788
/* [ from pcertdb.c - calls Ascii to Name ] */
789
/*
790
 * Lookup a certificate in the database by name
791
 */
792
CERTCertificate *
793
CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
794
0
{
795
0
    CERTName *name;
796
0
    SECItem *nameItem;
797
0
    CERTCertificate *cert = NULL;
798
0
    PLArenaPool *arena = NULL;
799
800
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
801
802
0
    if (arena == NULL) {
803
0
        goto loser;
804
0
    }
805
806
0
    name = CERT_AsciiToName(nameStr);
807
808
0
    if (name) {
809
0
        nameItem = SEC_ASN1EncodeItem(arena, NULL, (void *)name,
810
0
                                      CERT_NameTemplate);
811
0
        if (nameItem != NULL) {
812
0
            cert = CERT_FindCertByName(handle, nameItem);
813
0
        }
814
0
        CERT_DestroyName(name);
815
0
    }
816
817
0
loser:
818
0
    if (arena) {
819
0
        PORT_FreeArena(arena, PR_FALSE);
820
0
    }
821
822
0
    return (cert);
823
0
}
824
825
/* From certv3.c */
826
827
CERTCrlDistributionPoints *
828
CERT_FindCRLDistributionPoints(CERTCertificate *cert)
829
0
{
830
0
    SECItem encodedExtenValue;
831
0
    SECStatus rv;
832
0
    CERTCrlDistributionPoints *dps;
833
834
0
    encodedExtenValue.data = NULL;
835
0
    encodedExtenValue.len = 0;
836
837
0
    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS,
838
0
                            &encodedExtenValue);
839
0
    if (rv != SECSuccess) {
840
0
        return (NULL);
841
0
    }
842
843
0
    dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue);
844
845
0
    PORT_Free(encodedExtenValue.data);
846
847
0
    return dps;
848
0
}
849
850
/* From crl.c */
851
CERTSignedCrl *
852
CERT_ImportCRL(CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx)
853
0
{
854
0
    CERTSignedCrl *retCrl = NULL;
855
0
    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
856
0
    retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx,
857
0
                            CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
858
0
    PK11_FreeSlot(slot);
859
860
0
    return retCrl;
861
0
}
862
863
/* From certdb.c */
864
static SECStatus
865
cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted)
866
0
{
867
0
    SECStatus rv;
868
0
    SECItem *derCert;
869
0
    CERTCertificate *cert = NULL;
870
0
    CERTCertificate *newcert = NULL;
871
0
    CERTCertDBHandle *handle;
872
0
    CERTCertTrust trust;
873
0
    PRBool isca;
874
0
    char *nickname;
875
0
    unsigned int certtype;
876
0
    PRBool istemp = PR_FALSE;
877
878
0
    handle = CERT_GetDefaultCertDB();
879
880
0
    while (numcerts--) {
881
0
        derCert = certs;
882
0
        certs++;
883
884
        /* decode my certificate */
885
        /* This use is ok -- only looks at decoded parts, calls NewTemp later */
886
0
        newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
887
0
        if (newcert == NULL) {
888
0
            goto loser;
889
0
        }
890
891
0
        if (!trusted) {
892
            /* make sure that cert is valid */
893
0
            rv = CERT_CertTimesValid(newcert);
894
0
            if (rv == SECFailure) {
895
0
                goto endloop;
896
0
            }
897
0
        }
898
899
        /* does it have the CA extension */
900
901
        /*
902
         * Make sure that if this is an intermediate CA in the chain that
903
         * it was given permission by its signer to be a CA.
904
         */
905
0
        isca = CERT_IsCACert(newcert, &certtype);
906
907
0
        if (!isca) {
908
0
            if (!trusted) {
909
0
                goto endloop;
910
0
            }
911
0
            trust.sslFlags = CERTDB_VALID_CA;
912
0
            trust.emailFlags = CERTDB_VALID_CA;
913
0
            trust.objectSigningFlags = CERTDB_VALID_CA;
914
0
        } else {
915
            /* SSL ca's must have the ssl bit set */
916
0
            if ((certUsage == certUsageSSLCA) &&
917
0
                ((certtype & NS_CERT_TYPE_SSL_CA) != NS_CERT_TYPE_SSL_CA)) {
918
0
                goto endloop;
919
0
            }
920
921
            /* it passed all of the tests, so lets add it to the database */
922
            /* mark it as a CA */
923
0
            PORT_Memset((void *)&trust, 0, sizeof(trust));
924
0
            switch (certUsage) {
925
0
                case certUsageSSLCA:
926
0
                    trust.sslFlags = CERTDB_VALID_CA;
927
0
                    break;
928
0
                case certUsageUserCertImport:
929
0
                    if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
930
0
                        trust.sslFlags = CERTDB_VALID_CA;
931
0
                    }
932
0
                    if ((certtype & NS_CERT_TYPE_EMAIL_CA) ==
933
0
                        NS_CERT_TYPE_EMAIL_CA) {
934
0
                        trust.emailFlags = CERTDB_VALID_CA;
935
0
                    }
936
0
                    if ((certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA) ==
937
0
                        NS_CERT_TYPE_OBJECT_SIGNING_CA) {
938
0
                        trust.objectSigningFlags = CERTDB_VALID_CA;
939
0
                    }
940
0
                    break;
941
0
                default:
942
0
                    PORT_Assert(0);
943
0
                    break;
944
0
            }
945
0
        }
946
947
0
        cert = CERT_NewTempCertificate(handle, derCert, NULL,
948
0
                                       PR_FALSE, PR_FALSE);
949
0
        if (cert == NULL) {
950
0
            goto loser;
951
0
        }
952
953
        /* if the cert is temp, make it perm; otherwise we're done */
954
0
        rv = CERT_GetCertIsTemp(cert, &istemp);
955
0
        if (rv != SECSuccess) {
956
0
            goto loser;
957
0
        }
958
0
        if (istemp) {
959
            /* get a default nickname for it */
960
0
            nickname = CERT_MakeCANickname(cert);
961
962
0
            rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
963
964
            /* free the nickname */
965
0
            if (nickname) {
966
0
                PORT_Free(nickname);
967
0
            }
968
0
        } else {
969
0
            rv = SECSuccess;
970
0
        }
971
972
0
        if (rv != SECSuccess) {
973
0
            goto loser;
974
0
        }
975
976
0
    endloop:
977
0
        if (newcert) {
978
0
            CERT_DestroyCertificate(newcert);
979
0
            newcert = NULL;
980
0
        }
981
0
    }
982
983
0
    rv = SECSuccess;
984
0
    goto done;
985
0
loser:
986
0
    rv = SECFailure;
987
0
done:
988
989
0
    if (newcert) {
990
0
        CERT_DestroyCertificate(newcert);
991
0
        newcert = NULL;
992
0
    }
993
994
0
    if (cert) {
995
0
        CERT_DestroyCertificate(cert);
996
0
        cert = NULL;
997
0
    }
998
999
0
    return (rv);
1000
0
}
1001
1002
SECStatus
1003
CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage)
1004
0
{
1005
0
    return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE);
1006
0
}
1007
1008
SECStatus
1009
CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage)
1010
0
{
1011
0
    return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE);
1012
0
}
1013
1014
/* Moved from certdb.c */
1015
/*
1016
** CERT_CertChainFromCert
1017
**
1018
** Construct a CERTCertificateList consisting of the given certificate and all
1019
** of the issuer certs until we either get to a self-signed cert or can't find
1020
** an issuer.  Since we don't know how many certs are in the chain we have to
1021
** build a linked list first as we count them.
1022
*/
1023
1024
typedef struct certNode {
1025
    struct certNode *next;
1026
    CERTCertificate *cert;
1027
} certNode;
1028
1029
CERTCertificateList *
1030
CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
1031
                       PRBool includeRoot)
1032
8
{
1033
8
    CERTCertificateList *chain = NULL;
1034
8
    NSSCertificate **stanChain;
1035
8
    NSSCertificate *stanCert;
1036
8
    PLArenaPool *arena;
1037
8
    NSSUsage nssUsage;
1038
8
    int i, len;
1039
8
    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
1040
8
    NSSCryptoContext *cc = STAN_GetDefaultCryptoContext();
1041
1042
8
    stanCert = STAN_GetNSSCertificate(cert);
1043
8
    if (!stanCert) {
1044
        /* error code is set */
1045
0
        return NULL;
1046
0
    }
1047
8
    nssUsage.anyUsage = PR_FALSE;
1048
8
    nssUsage.nss3usage = usage;
1049
8
    nssUsage.nss3lookingForCA = PR_FALSE;
1050
8
    stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL,
1051
8
                                          CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc);
1052
8
    if (!stanChain) {
1053
0
        PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
1054
0
        return NULL;
1055
0
    }
1056
1057
8
    len = 0;
1058
8
    stanCert = stanChain[0];
1059
16
    while (stanCert) {
1060
8
        stanCert = stanChain[++len];
1061
8
    }
1062
1063
8
    arena = PORT_NewArena(4096);
1064
8
    if (arena == NULL) {
1065
0
        goto loser;
1066
0
    }
1067
1068
8
    chain = (CERTCertificateList *)PORT_ArenaAlloc(arena,
1069
8
                                                   sizeof(CERTCertificateList));
1070
8
    if (!chain)
1071
0
        goto loser;
1072
8
    chain->certs = (SECItem *)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
1073
8
    if (!chain->certs)
1074
0
        goto loser;
1075
8
    i = 0;
1076
8
    stanCert = stanChain[i];
1077
16
    while (stanCert) {
1078
8
        SECItem derCert;
1079
8
        CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
1080
8
        if (!cCert) {
1081
0
            goto loser;
1082
0
        }
1083
8
        derCert.len = (unsigned int)stanCert->encoding.size;
1084
8
        derCert.data = (unsigned char *)stanCert->encoding.data;
1085
8
        derCert.type = siBuffer;
1086
8
        if (SECITEM_CopyItem(arena, &chain->certs[i], &derCert) != SECSuccess) {
1087
0
            CERT_DestroyCertificate(cCert);
1088
0
            goto loser;
1089
0
        }
1090
8
        stanCert = stanChain[++i];
1091
8
        if (!stanCert && !cCert->isRoot) {
1092
            /* reached the end of the chain, but the final cert is
1093
             * not a root.  Don't discard it.
1094
             */
1095
0
            includeRoot = PR_TRUE;
1096
0
        }
1097
8
        CERT_DestroyCertificate(cCert);
1098
8
    }
1099
8
    if (!includeRoot && len > 1) {
1100
0
        chain->len = len - 1;
1101
8
    } else {
1102
8
        chain->len = len;
1103
8
    }
1104
1105
8
    chain->arena = arena;
1106
8
    nss_ZFreeIf(stanChain);
1107
8
    return chain;
1108
0
loser:
1109
0
    i = 0;
1110
0
    stanCert = stanChain[i];
1111
0
    while (stanCert) {
1112
0
        CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
1113
0
        if (cCert) {
1114
0
            CERT_DestroyCertificate(cCert);
1115
0
        }
1116
0
        stanCert = stanChain[++i];
1117
0
    }
1118
0
    nss_ZFreeIf(stanChain);
1119
0
    if (arena) {
1120
0
        PORT_FreeArena(arena, PR_FALSE);
1121
0
    }
1122
0
    return NULL;
1123
8
}
1124
1125
/* Builds a CERTCertificateList holding just one DER-encoded cert, namely
1126
** the one for the cert passed as an argument.
1127
*/
1128
CERTCertificateList *
1129
CERT_CertListFromCert(CERTCertificate *cert)
1130
0
{
1131
0
    CERTCertificateList *chain = NULL;
1132
0
    int rv;
1133
0
    PLArenaPool *arena;
1134
1135
    /* arena for SecCertificateList */
1136
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1137
0
    if (arena == NULL)
1138
0
        goto no_memory;
1139
1140
    /* build the CERTCertificateList */
1141
0
    chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
1142
0
    if (chain == NULL)
1143
0
        goto no_memory;
1144
0
    chain->certs = (SECItem *)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem));
1145
0
    if (chain->certs == NULL)
1146
0
        goto no_memory;
1147
0
    rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert));
1148
0
    if (rv < 0)
1149
0
        goto loser;
1150
0
    chain->len = 1;
1151
0
    chain->arena = arena;
1152
1153
0
    return chain;
1154
1155
0
no_memory:
1156
0
    PORT_SetError(SEC_ERROR_NO_MEMORY);
1157
0
loser:
1158
0
    if (arena != NULL) {
1159
0
        PORT_FreeArena(arena, PR_FALSE);
1160
0
    }
1161
0
    return NULL;
1162
0
}
1163
1164
CERTCertificateList *
1165
CERT_DupCertList(const CERTCertificateList *oldList)
1166
65.2k
{
1167
65.2k
    CERTCertificateList *newList = NULL;
1168
65.2k
    PLArenaPool *arena = NULL;
1169
65.2k
    SECItem *newItem;
1170
65.2k
    SECItem *oldItem;
1171
65.2k
    int len = oldList->len;
1172
65.2k
    int rv;
1173
1174
    /* arena for SecCertificateList */
1175
65.2k
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1176
65.2k
    if (arena == NULL)
1177
0
        goto no_memory;
1178
1179
    /* now build the CERTCertificateList */
1180
65.2k
    newList = PORT_ArenaNew(arena, CERTCertificateList);
1181
65.2k
    if (newList == NULL)
1182
0
        goto no_memory;
1183
65.2k
    newList->arena = arena;
1184
65.2k
    newItem = (SECItem *)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
1185
65.2k
    if (newItem == NULL)
1186
0
        goto no_memory;
1187
65.2k
    newList->certs = newItem;
1188
65.2k
    newList->len = len;
1189
1190
130k
    for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) {
1191
65.2k
        rv = SECITEM_CopyItem(arena, newItem, oldItem);
1192
65.2k
        if (rv < 0)
1193
0
            goto loser;
1194
65.2k
    }
1195
65.2k
    return newList;
1196
1197
0
no_memory:
1198
0
    PORT_SetError(SEC_ERROR_NO_MEMORY);
1199
0
loser:
1200
0
    if (arena != NULL) {
1201
0
        PORT_FreeArena(arena, PR_FALSE);
1202
0
    }
1203
0
    return NULL;
1204
0
}
1205
1206
void
1207
CERT_DestroyCertificateList(CERTCertificateList *list)
1208
65.2k
{
1209
65.2k
    PORT_FreeArena(list->arena, PR_FALSE);
1210
65.2k
}