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