Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / certhigh / certhigh.c
blob6f4963f7eba4761ecbea3bd32fb704d4e75bb721
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
36 #include "nspr.h"
37 #include "secerr.h"
38 #include "secasn1.h"
39 #include "seccomon.h"
40 #include "pk11func.h"
41 #include "certdb.h"
42 #include "certt.h"
43 #include "cert.h"
44 #include "certxutl.h"
46 #include "nsspki.h"
47 #include "pki.h"
48 #include "pkit.h"
49 #include "pkitm.h"
50 #include "pki3hack.h"
53 PRBool
54 CERT_MatchNickname(char *name1, char *name2) {
55 char *nickname1= NULL;
56 char *nickname2 = NULL;
57 char *token1;
58 char *token2;
59 char *token = NULL;
60 int len;
62 /* first deal with the straight comparison */
63 if (PORT_Strcmp(name1, name2) == 0) {
64 return PR_TRUE;
66 /* we need to handle the case where one name has an explicit token and the other
67 * doesn't */
68 token1 = PORT_Strchr(name1,':');
69 token2 = PORT_Strchr(name2,':');
70 if ((token1 && token2) || (!token1 && !token2)) {
71 /* either both token names are specified or neither are, not match */
72 return PR_FALSE;
74 if (token1) {
75 token=name1;
76 nickname1=token1;
77 nickname2=name2;
78 } else {
79 token=name2;
80 nickname1=token2;
81 nickname2=name1;
83 len = nickname1-token;
84 nickname1++;
85 if (PORT_Strcmp(nickname1,nickname2) != 0) {
86 return PR_FALSE;
88 /* compare the other token with the internal slot here */
89 return PR_TRUE;
93 * Find all user certificates that match the given criteria.
95 * "handle" - database to search
96 * "usage" - certificate usage to match
97 * "oneCertPerName" - if set then only return the "best" cert per
98 * name
99 * "validOnly" - only return certs that are curently valid
100 * "proto_win" - window handle passed to pkcs11
102 CERTCertList *
103 CERT_FindUserCertsByUsage(CERTCertDBHandle *handle,
104 SECCertUsage usage,
105 PRBool oneCertPerName,
106 PRBool validOnly,
107 void *proto_win)
109 CERTCertNicknames *nicknames = NULL;
110 char **nnptr;
111 int nn;
112 CERTCertificate *cert = NULL;
113 CERTCertList *certList = NULL;
114 SECStatus rv;
115 int64 time;
116 CERTCertListNode *node = NULL;
117 CERTCertListNode *freenode = NULL;
118 int n;
120 time = PR_Now();
122 nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER,
123 proto_win);
125 if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) {
126 goto loser;
129 nnptr = nicknames->nicknames;
130 nn = nicknames->numnicknames;
132 while ( nn > 0 ) {
133 cert = NULL;
134 /* use the pk11 call so that we pick up any certs on tokens,
135 * which may require login
137 if ( proto_win != NULL ) {
138 cert = PK11_FindCertFromNickname(*nnptr,proto_win);
141 /* Sigh, It turns out if the cert is already in the temp db, because
142 * it's in the perm db, then the nickname lookup doesn't work.
143 * since we already have the cert here, though, than we can just call
144 * CERT_CreateSubjectCertList directly. For those cases where we didn't
145 * find the cert in pkcs #11 (because we didn't have a password arg,
146 * or because the nickname is for a peer, server, or CA cert, then we
147 * go look the cert up.
149 if (cert == NULL) {
150 cert = CERT_FindCertByNickname(handle,*nnptr);
153 if ( cert != NULL ) {
154 /* collect certs for this nickname, sorting them into the list */
155 certList = CERT_CreateSubjectCertList(certList, handle,
156 &cert->derSubject, time, validOnly);
158 CERT_FilterCertListForUserCerts(certList);
160 /* drop the extra reference */
161 CERT_DestroyCertificate(cert);
164 nnptr++;
165 nn--;
168 /* remove certs with incorrect usage */
169 rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
171 if ( rv != SECSuccess ) {
172 goto loser;
175 /* remove any extra certs for each name */
176 if ( oneCertPerName ) {
177 PRBool *flags;
179 nn = nicknames->numnicknames;
180 nnptr = nicknames->nicknames;
182 flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn);
183 if ( flags == NULL ) {
184 goto loser;
187 node = CERT_LIST_HEAD(certList);
189 /* treverse all certs in the list */
190 while ( !CERT_LIST_END(node, certList) ) {
192 /* find matching nickname index */
193 for ( n = 0; n < nn; n++ ) {
194 if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) {
195 /* We found a match. If this is the first one, then
196 * set the flag and move on to the next cert. If this
197 * is not the first one then delete it from the list.
199 if ( flags[n] ) {
200 /* We have already seen a cert with this nickname,
201 * so delete this one.
203 freenode = node;
204 node = CERT_LIST_NEXT(node);
205 CERT_RemoveCertListNode(freenode);
206 } else {
207 /* keep the first cert for each nickname, but set the
208 * flag so we know to delete any others with the same
209 * nickname.
211 flags[n] = PR_TRUE;
212 node = CERT_LIST_NEXT(node);
214 break;
217 if ( n == nn ) {
218 /* if we get here it means that we didn't find a matching
219 * nickname, which should not happen.
221 PORT_Assert(0);
222 node = CERT_LIST_NEXT(node);
225 PORT_Free(flags);
228 goto done;
230 loser:
231 if ( certList != NULL ) {
232 CERT_DestroyCertList(certList);
233 certList = NULL;
236 done:
237 if ( nicknames != NULL ) {
238 CERT_FreeNicknames(nicknames);
241 return(certList);
245 * Find a user certificate that matchs the given criteria.
247 * "handle" - database to search
248 * "nickname" - nickname to match
249 * "usage" - certificate usage to match
250 * "validOnly" - only return certs that are curently valid
251 * "proto_win" - window handle passed to pkcs11
253 CERTCertificate *
254 CERT_FindUserCertByUsage(CERTCertDBHandle *handle,
255 const char *nickname,
256 SECCertUsage usage,
257 PRBool validOnly,
258 void *proto_win)
260 CERTCertificate *cert = NULL;
261 CERTCertList *certList = NULL;
262 SECStatus rv;
263 int64 time;
265 time = PR_Now();
267 /* use the pk11 call so that we pick up any certs on tokens,
268 * which may require login
270 /* XXX - why is this restricted? */
271 if ( proto_win != NULL ) {
272 cert = PK11_FindCertFromNickname(nickname,proto_win);
276 /* sigh, There are still problems find smart cards from the temp
277 * db. This will get smart cards working again. The real fix
278 * is to make sure we can search the temp db by their token nickname.
280 if (cert == NULL) {
281 cert = CERT_FindCertByNickname(handle,nickname);
284 if ( cert != NULL ) {
285 unsigned int requiredKeyUsage;
286 unsigned int requiredCertType;
288 rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE,
289 &requiredKeyUsage, &requiredCertType);
290 if ( rv != SECSuccess ) {
291 /* drop the extra reference */
292 CERT_DestroyCertificate(cert);
293 cert = NULL;
294 goto loser;
296 /* If we already found the right cert, just return it */
297 if ( (!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE)
298 == secCertTimeValid) &&
299 (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) &&
300 (cert->nsCertType & requiredCertType) &&
301 CERT_IsUserCert(cert) ) {
302 return(cert);
305 /* collect certs for this nickname, sorting them into the list */
306 certList = CERT_CreateSubjectCertList(certList, handle,
307 &cert->derSubject, time, validOnly);
309 CERT_FilterCertListForUserCerts(certList);
311 /* drop the extra reference */
312 CERT_DestroyCertificate(cert);
313 cert = NULL;
316 if ( certList == NULL ) {
317 goto loser;
320 /* remove certs with incorrect usage */
321 rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
323 if ( rv != SECSuccess ) {
324 goto loser;
327 if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) {
328 cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
331 loser:
332 if ( certList != NULL ) {
333 CERT_DestroyCertList(certList);
336 return(cert);
339 CERTCertList *
340 CERT_MatchUserCert(CERTCertDBHandle *handle,
341 SECCertUsage usage,
342 int nCANames, char **caNames,
343 void *proto_win)
345 CERTCertList *certList = NULL;
346 SECStatus rv;
348 certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE,
349 proto_win);
350 if ( certList == NULL ) {
351 goto loser;
354 rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage);
355 if ( rv != SECSuccess ) {
356 goto loser;
359 goto done;
361 loser:
362 if ( certList != NULL ) {
363 CERT_DestroyCertList(certList);
364 certList = NULL;
367 done:
369 return(certList);
373 typedef struct stringNode {
374 struct stringNode *next;
375 char *string;
376 } stringNode;
378 static PRStatus
379 CollectNicknames( NSSCertificate *c, void *data)
381 CERTCertNicknames *names;
382 PRBool saveit = PR_FALSE;
383 stringNode *node;
384 int len;
385 #ifdef notdef
386 NSSTrustDomain *td;
387 NSSTrust *trust;
388 #endif
389 char *stanNickname;
390 char *nickname = NULL;
392 names = (CERTCertNicknames *)data;
394 stanNickname = nssCertificate_GetNickname(c,NULL);
396 if ( stanNickname ) {
397 if (names->what == SEC_CERT_NICKNAMES_USER) {
398 saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL);
400 #ifdef notdef
401 else {
402 td = NSSCertificate_GetTrustDomain(c);
403 if (!td) {
404 return PR_SUCCESS;
406 trust = nssTrustDomain_FindTrustForCertificate(td,c);
408 switch(names->what) {
409 case SEC_CERT_NICKNAMES_ALL:
410 if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
411 (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
412 (trust->objectSigningFlags &
413 (CERTDB_VALID_CA|CERTDB_VALID_PEER))) {
414 saveit = PR_TRUE;
417 break;
418 case SEC_CERT_NICKNAMES_SERVER:
419 if ( trust->sslFlags & CERTDB_VALID_PEER ) {
420 saveit = PR_TRUE;
423 break;
424 case SEC_CERT_NICKNAMES_CA:
425 if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)||
426 ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) ||
427 ((trust->objectSigningFlags & CERTDB_VALID_CA )
428 == CERTDB_VALID_CA)) {
429 saveit = PR_TRUE;
431 break;
434 #endif
437 /* traverse the list of collected nicknames and make sure we don't make
438 * a duplicate
440 if ( saveit ) {
441 nickname = STAN_GetCERTCertificateName(NULL, c);
442 /* nickname can only be NULL here if we are having memory
443 * alloc problems */
444 if (nickname == NULL) {
445 return PR_FAILURE;
447 node = (stringNode *)names->head;
448 while ( node != NULL ) {
449 if ( PORT_Strcmp(nickname, node->string) == 0 ) {
450 /* if the string matches, then don't save this one */
451 saveit = PR_FALSE;
452 break;
454 node = node->next;
458 if ( saveit ) {
460 /* allocate the node */
461 node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
462 if ( node == NULL ) {
463 PORT_Free(nickname);
464 return PR_FAILURE;
467 /* copy the string */
468 len = PORT_Strlen(nickname) + 1;
469 node->string = (char*)PORT_ArenaAlloc(names->arena, len);
470 if ( node->string == NULL ) {
471 PORT_Free(nickname);
472 return PR_FAILURE;
474 PORT_Memcpy(node->string, nickname, len);
476 /* link it into the list */
477 node->next = (stringNode *)names->head;
478 names->head = (void *)node;
480 /* bump the count */
481 names->numnicknames++;
484 if (nickname) PORT_Free(nickname);
485 return(PR_SUCCESS);
488 CERTCertNicknames *
489 CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
491 PRArenaPool *arena;
492 CERTCertNicknames *names;
493 int i;
494 stringNode *node;
496 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
497 if ( arena == NULL ) {
498 PORT_SetError(SEC_ERROR_NO_MEMORY);
499 return(NULL);
502 names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
503 if ( names == NULL ) {
504 goto loser;
507 names->arena = arena;
508 names->head = NULL;
509 names->numnicknames = 0;
510 names->nicknames = NULL;
511 names->what = what;
512 names->totallen = 0;
514 /* make sure we are logged in */
515 (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
517 NSSTrustDomain_TraverseCertificates(handle,
518 CollectNicknames, (void *)names);
519 if ( names->numnicknames ) {
520 names->nicknames = (char**)PORT_ArenaAlloc(arena,
521 names->numnicknames * sizeof(char *));
523 if ( names->nicknames == NULL ) {
524 goto loser;
527 node = (stringNode *)names->head;
529 for ( i = 0; i < names->numnicknames; i++ ) {
530 PORT_Assert(node != NULL);
532 names->nicknames[i] = node->string;
533 names->totallen += PORT_Strlen(node->string);
534 node = node->next;
537 PORT_Assert(node == NULL);
540 return(names);
542 loser:
543 PORT_FreeArena(arena, PR_FALSE);
544 return(NULL);
547 void
548 CERT_FreeNicknames(CERTCertNicknames *nicknames)
550 PORT_FreeArena(nicknames->arena, PR_FALSE);
552 return;
555 /* [ FROM pcertdb.c ] */
557 typedef struct dnameNode {
558 struct dnameNode *next;
559 SECItem name;
560 } dnameNode;
562 void
563 CERT_FreeDistNames(CERTDistNames *names)
565 PORT_FreeArena(names->arena, PR_FALSE);
567 return;
570 static SECStatus
571 CollectDistNames( CERTCertificate *cert, SECItem *k, void *data)
573 CERTDistNames *names;
574 PRBool saveit = PR_FALSE;
575 CERTCertTrust *trust;
576 dnameNode *node;
577 int len;
579 names = (CERTDistNames *)data;
581 if ( cert->trust ) {
582 trust = cert->trust;
584 /* only collect names of CAs trusted for issuing SSL clients */
585 if ( trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ) {
586 saveit = PR_TRUE;
590 if ( saveit ) {
591 /* allocate the node */
592 node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode));
593 if ( node == NULL ) {
594 return(SECFailure);
597 /* copy the name */
598 node->name.len = len = cert->derSubject.len;
599 node->name.type = siBuffer;
600 node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len);
601 if ( node->name.data == NULL ) {
602 return(SECFailure);
604 PORT_Memcpy(node->name.data, cert->derSubject.data, len);
606 /* link it into the list */
607 node->next = (dnameNode *)names->head;
608 names->head = (void *)node;
610 /* bump the count */
611 names->nnames++;
614 return(SECSuccess);
618 * Return all of the CAs that are "trusted" for SSL.
620 CERTDistNames *
621 CERT_GetSSLCACerts(CERTCertDBHandle *handle)
623 PRArenaPool *arena;
624 CERTDistNames *names;
625 int i;
626 SECStatus rv;
627 dnameNode *node;
629 /* allocate an arena to use */
630 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
631 if ( arena == NULL ) {
632 PORT_SetError(SEC_ERROR_NO_MEMORY);
633 return(NULL);
636 /* allocate the header structure */
637 names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
638 if ( names == NULL ) {
639 goto loser;
642 /* initialize the header struct */
643 names->arena = arena;
644 names->head = NULL;
645 names->nnames = 0;
646 names->names = NULL;
648 /* collect the names from the database */
649 rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL);
650 if ( rv ) {
651 goto loser;
654 /* construct the array from the list */
655 if ( names->nnames ) {
656 names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem));
658 if ( names->names == NULL ) {
659 goto loser;
662 node = (dnameNode *)names->head;
664 for ( i = 0; i < names->nnames; i++ ) {
665 PORT_Assert(node != NULL);
667 names->names[i] = node->name;
668 node = node->next;
671 PORT_Assert(node == NULL);
674 return(names);
676 loser:
677 PORT_FreeArena(arena, PR_FALSE);
678 return(NULL);
681 CERTDistNames *
682 CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
683 int nnames)
685 CERTDistNames *dnames = NULL;
686 PRArenaPool *arena;
687 int i, rv;
688 SECItem *names = NULL;
689 CERTCertificate *cert = NULL;
691 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
692 if (arena == NULL) goto loser;
693 dnames = PORT_ArenaZNew(arena, CERTDistNames);
694 if (dnames == NULL) goto loser;
696 dnames->arena = arena;
697 dnames->nnames = nnames;
698 dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
699 if (names == NULL) goto loser;
701 for (i = 0; i < nnames; i++) {
702 cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]);
703 if (cert == NULL) goto loser;
704 rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject);
705 if (rv == SECFailure) goto loser;
706 CERT_DestroyCertificate(cert);
708 return dnames;
710 loser:
711 if (cert != NULL)
712 CERT_DestroyCertificate(cert);
713 if (arena != NULL)
714 PORT_FreeArena(arena, PR_FALSE);
715 return NULL;
718 /* [ from pcertdb.c - calls Ascii to Name ] */
720 * Lookup a certificate in the database by name
722 CERTCertificate *
723 CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
725 CERTName *name;
726 SECItem *nameItem;
727 CERTCertificate *cert = NULL;
728 PRArenaPool *arena = NULL;
730 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
732 if ( arena == NULL ) {
733 goto loser;
736 name = CERT_AsciiToName(nameStr);
738 if ( name ) {
739 nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name,
740 CERT_NameTemplate);
741 if ( nameItem != NULL ) {
742 cert = CERT_FindCertByName(handle, nameItem);
744 CERT_DestroyName(name);
747 loser:
748 if ( arena ) {
749 PORT_FreeArena(arena, PR_FALSE);
752 return(cert);
755 /* From certv3.c */
757 CERTCrlDistributionPoints *
758 CERT_FindCRLDistributionPoints (CERTCertificate *cert)
760 SECItem encodedExtenValue;
761 SECStatus rv;
762 CERTCrlDistributionPoints *dps;
764 encodedExtenValue.data = NULL;
765 encodedExtenValue.len = 0;
767 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS,
768 &encodedExtenValue);
769 if ( rv != SECSuccess ) {
770 return (NULL);
773 dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue);
775 PORT_Free(encodedExtenValue.data);
777 return dps;
780 /* From crl.c */
781 CERTSignedCrl * CERT_ImportCRL
782 (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx)
784 CERTSignedCrl* retCrl = NULL;
785 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
786 retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx,
787 CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
788 PK11_FreeSlot(slot);
790 return retCrl;
793 /* From certdb.c */
794 static SECStatus
795 cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted)
797 SECStatus rv;
798 SECItem *derCert;
799 CERTCertificate *cert = NULL;
800 CERTCertificate *newcert = NULL;
801 CERTCertDBHandle *handle;
802 CERTCertTrust trust;
803 PRBool isca;
804 char *nickname;
805 unsigned int certtype;
807 handle = CERT_GetDefaultCertDB();
809 while (numcerts--) {
810 derCert = certs;
811 certs++;
813 /* decode my certificate */
814 /* This use is ok -- only looks at decoded parts, calls NewTemp later */
815 newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
816 if ( newcert == NULL ) {
817 goto loser;
820 if (!trusted) {
821 /* make sure that cert is valid */
822 rv = CERT_CertTimesValid(newcert);
823 if ( rv == SECFailure ) {
824 goto endloop;
828 /* does it have the CA extension */
831 * Make sure that if this is an intermediate CA in the chain that
832 * it was given permission by its signer to be a CA.
834 isca = CERT_IsCACert(newcert, &certtype);
836 if ( !isca ) {
837 if (!trusted) {
838 goto endloop;
840 trust.sslFlags = CERTDB_VALID_CA;
841 trust.emailFlags = CERTDB_VALID_CA;
842 trust.objectSigningFlags = CERTDB_VALID_CA;
843 } else {
844 /* SSL ca's must have the ssl bit set */
845 if ( ( certUsage == certUsageSSLCA ) &&
846 (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) {
847 goto endloop;
850 /* it passed all of the tests, so lets add it to the database */
851 /* mark it as a CA */
852 PORT_Memset((void *)&trust, 0, sizeof(trust));
853 switch ( certUsage ) {
854 case certUsageSSLCA:
855 trust.sslFlags = CERTDB_VALID_CA;
856 break;
857 case certUsageUserCertImport:
858 if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
859 trust.sslFlags = CERTDB_VALID_CA;
861 if ((certtype & NS_CERT_TYPE_EMAIL_CA)
862 == NS_CERT_TYPE_EMAIL_CA ) {
863 trust.emailFlags = CERTDB_VALID_CA;
865 if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) ==
866 NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
867 trust.objectSigningFlags = CERTDB_VALID_CA;
869 break;
870 default:
871 PORT_Assert(0);
872 break;
876 cert = CERT_NewTempCertificate(handle, derCert, NULL,
877 PR_FALSE, PR_FALSE);
878 if ( cert == NULL ) {
879 goto loser;
882 /* if the cert is temp, make it perm; otherwise we're done */
883 if (cert->istemp) {
884 /* get a default nickname for it */
885 nickname = CERT_MakeCANickname(cert);
887 rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
889 /* free the nickname */
890 if ( nickname ) {
891 PORT_Free(nickname);
893 } else {
894 rv = SECSuccess;
897 CERT_DestroyCertificate(cert);
898 cert = NULL;
900 if ( rv != SECSuccess ) {
901 goto loser;
904 endloop:
905 if ( newcert ) {
906 CERT_DestroyCertificate(newcert);
907 newcert = NULL;
912 rv = SECSuccess;
913 goto done;
914 loser:
915 rv = SECFailure;
916 done:
918 if ( newcert ) {
919 CERT_DestroyCertificate(newcert);
920 newcert = NULL;
923 if ( cert ) {
924 CERT_DestroyCertificate(cert);
925 cert = NULL;
928 return(rv);
931 SECStatus
932 CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage)
934 return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE);
937 SECStatus
938 CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) {
939 return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE);
942 /* Moved from certdb.c */
944 ** CERT_CertChainFromCert
946 ** Construct a CERTCertificateList consisting of the given certificate and all
947 ** of the issuer certs until we either get to a self-signed cert or can't find
948 ** an issuer. Since we don't know how many certs are in the chain we have to
949 ** build a linked list first as we count them.
952 typedef struct certNode {
953 struct certNode *next;
954 CERTCertificate *cert;
955 } certNode;
957 CERTCertificateList *
958 CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
959 PRBool includeRoot)
961 CERTCertificateList *chain = NULL;
962 NSSCertificate **stanChain;
963 NSSCertificate *stanCert;
964 PRArenaPool *arena;
965 NSSUsage nssUsage;
966 int i, len;
967 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
968 NSSCryptoContext *cc = STAN_GetDefaultCryptoContext();
970 stanCert = STAN_GetNSSCertificate(cert);
971 if (!stanCert) {
972 /* error code is set */
973 return NULL;
975 nssUsage.anyUsage = PR_FALSE;
976 nssUsage.nss3usage = usage;
977 nssUsage.nss3lookingForCA = PR_FALSE;
978 stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL,
979 CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc);
980 if (!stanChain) {
981 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
982 return NULL;
985 len = 0;
986 stanCert = stanChain[0];
987 while (stanCert) {
988 stanCert = stanChain[++len];
991 arena = PORT_NewArena(4096);
992 if (arena == NULL) {
993 goto loser;
996 chain = (CERTCertificateList *)PORT_ArenaAlloc(arena,
997 sizeof(CERTCertificateList));
998 if (!chain) goto loser;
999 chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
1000 if (!chain->certs) goto loser;
1001 i = 0;
1002 stanCert = stanChain[i];
1003 while (stanCert) {
1004 SECItem derCert;
1005 CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
1006 if (!cCert) {
1007 goto loser;
1009 derCert.len = (unsigned int)stanCert->encoding.size;
1010 derCert.data = (unsigned char *)stanCert->encoding.data;
1011 derCert.type = siBuffer;
1012 SECITEM_CopyItem(arena, &chain->certs[i], &derCert);
1013 stanCert = stanChain[++i];
1014 if (!stanCert && !cCert->isRoot) {
1015 /* reached the end of the chain, but the final cert is
1016 * not a root. Don't discard it.
1018 includeRoot = PR_TRUE;
1020 CERT_DestroyCertificate(cCert);
1022 if ( !includeRoot && len > 1) {
1023 chain->len = len - 1;
1024 } else {
1025 chain->len = len;
1028 chain->arena = arena;
1029 nss_ZFreeIf(stanChain);
1030 return chain;
1031 loser:
1032 i = 0;
1033 stanCert = stanChain[i];
1034 while (stanCert) {
1035 CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
1036 if (cCert) {
1037 CERT_DestroyCertificate(cCert);
1039 stanCert = stanChain[++i];
1041 nss_ZFreeIf(stanChain);
1042 if (arena) {
1043 PORT_FreeArena(arena, PR_FALSE);
1045 return NULL;
1048 /* Builds a CERTCertificateList holding just one DER-encoded cert, namely
1049 ** the one for the cert passed as an argument.
1051 CERTCertificateList *
1052 CERT_CertListFromCert(CERTCertificate *cert)
1054 CERTCertificateList *chain = NULL;
1055 int rv;
1056 PRArenaPool *arena;
1058 /* arena for SecCertificateList */
1059 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1060 if (arena == NULL) goto no_memory;
1062 /* build the CERTCertificateList */
1063 chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
1064 if (chain == NULL) goto no_memory;
1065 chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem));
1066 if (chain->certs == NULL) goto no_memory;
1067 rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert));
1068 if (rv < 0) goto loser;
1069 chain->len = 1;
1070 chain->arena = arena;
1072 return chain;
1074 no_memory:
1075 PORT_SetError(SEC_ERROR_NO_MEMORY);
1076 loser:
1077 if (arena != NULL) {
1078 PORT_FreeArena(arena, PR_FALSE);
1080 return NULL;
1083 CERTCertificateList *
1084 CERT_DupCertList(CERTCertificateList * oldList)
1086 CERTCertificateList *newList = NULL;
1087 PRArenaPool *arena = NULL;
1088 SECItem *newItem;
1089 SECItem *oldItem;
1090 int len = oldList->len;
1091 int rv;
1093 /* arena for SecCertificateList */
1094 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1095 if (arena == NULL)
1096 goto no_memory;
1098 /* now build the CERTCertificateList */
1099 newList = PORT_ArenaNew(arena, CERTCertificateList);
1100 if (newList == NULL)
1101 goto no_memory;
1102 newList->arena = arena;
1103 newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
1104 if (newItem == NULL)
1105 goto no_memory;
1106 newList->certs = newItem;
1107 newList->len = len;
1109 for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) {
1110 rv = SECITEM_CopyItem(arena, newItem, oldItem);
1111 if (rv < 0)
1112 goto loser;
1114 return newList;
1116 no_memory:
1117 PORT_SetError(SEC_ERROR_NO_MEMORY);
1118 loser:
1119 if (arena != NULL) {
1120 PORT_FreeArena(arena, PR_FALSE);
1122 return NULL;
1125 void
1126 CERT_DestroyCertificateList(CERTCertificateList *list)
1128 PORT_FreeArena(list->arena, PR_FALSE);