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