Back to index

lightning-sunbird  0.9+nobinonly
certhigh.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 #include "nspr.h"
00037 #include "secerr.h"
00038 #include "secasn1.h"
00039 #include "seccomon.h"
00040 #include "pk11func.h"
00041 #include "certdb.h"
00042 #include "certt.h"
00043 #include "cert.h"
00044 #include "certxutl.h"
00045 
00046 #ifndef NSS_3_4_CODE
00047 #define NSS_3_4_CODE
00048 #endif
00049 #include "nsspki.h"
00050 #include "pki.h"
00051 #include "pkit.h"
00052 #include "pkitm.h"
00053 #include "pki3hack.h"
00054 
00055 
00056 PRBool
00057 CERT_MatchNickname(char *name1, char *name2) {
00058     char *nickname1= NULL;
00059     char *nickname2 = NULL;
00060     char *token1;
00061     char *token2;
00062     char *token = NULL;
00063     int len;
00064 
00065     /* first deal with the straight comparison */
00066     if (PORT_Strcmp(name1, name2) == 0) {
00067        return PR_TRUE;
00068     }
00069     /* we need to handle the case where one name has an explicit token and the other
00070      * doesn't */
00071     token1 = PORT_Strchr(name1,':');
00072     token2 = PORT_Strchr(name2,':');
00073     if ((token1 && token2) || (!token1 && !token2)) {
00074        /* either both token names are specified or neither are, not match */
00075        return PR_FALSE;
00076     }
00077     if (token1) {
00078        token=name1;
00079        nickname1=token1;
00080        nickname2=name2;
00081     } else {
00082        token=name2;
00083        nickname1=token2;
00084        nickname2=name1;
00085     }
00086     len = nickname1-token;
00087     nickname1++;
00088     if (PORT_Strcmp(nickname1,nickname2) != 0) {
00089        return PR_FALSE;
00090     }
00091     /* compare the other token with the internal slot here */
00092     return PR_TRUE;
00093 }
00094 
00095 /*
00096  * Find all user certificates that match the given criteria.
00097  * 
00098  *     "handle" - database to search
00099  *     "usage" - certificate usage to match
00100  *     "oneCertPerName" - if set then only return the "best" cert per
00101  *                   name
00102  *     "validOnly" - only return certs that are curently valid
00103  *     "proto_win" - window handle passed to pkcs11
00104  */
00105 CERTCertList *
00106 CERT_FindUserCertsByUsage(CERTCertDBHandle *handle,
00107                        SECCertUsage usage,
00108                        PRBool oneCertPerName,
00109                        PRBool validOnly,
00110                        void *proto_win)
00111 {
00112     CERTCertNicknames *nicknames = NULL;
00113     char **nnptr;
00114     int nn;
00115     CERTCertificate *cert = NULL;
00116     CERTCertList *certList = NULL;
00117     SECStatus rv;
00118     int64 time;
00119     CERTCertListNode *node = NULL;
00120     CERTCertListNode *freenode = NULL;
00121     int n;
00122     
00123     time = PR_Now();
00124     
00125     nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER,
00126                                   proto_win);
00127     
00128     if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) {
00129        goto loser;
00130     }
00131 
00132     nnptr = nicknames->nicknames;
00133     nn = nicknames->numnicknames;
00134 
00135     while ( nn > 0 ) {
00136        cert = NULL;
00137        /* use the pk11 call so that we pick up any certs on tokens,
00138         * which may require login
00139         */
00140        if ( proto_win != NULL ) {
00141            cert = PK11_FindCertFromNickname(*nnptr,proto_win);
00142        }
00143 
00144        /* Sigh, It turns out if the cert is already in the temp db, because
00145         * it's in the perm db, then the nickname lookup doesn't work.
00146         * since we already have the cert here, though, than we can just call
00147         * CERT_CreateSubjectCertList directly. For those cases where we didn't
00148         * find the cert in pkcs #11 (because we didn't have a password arg,
00149         * or because the nickname is for a peer, server, or CA cert, then we
00150         * go look the cert up.
00151         */
00152        if (cert == NULL) { 
00153            cert = CERT_FindCertByNickname(handle,*nnptr);
00154        }
00155 
00156        if ( cert != NULL ) {
00157           /* collect certs for this nickname, sorting them into the list */
00158            certList = CERT_CreateSubjectCertList(certList, handle, 
00159                             &cert->derSubject, time, validOnly);
00160 
00161            CERT_FilterCertListForUserCerts(certList);
00162        
00163            /* drop the extra reference */
00164            CERT_DestroyCertificate(cert);
00165        }
00166        
00167        nnptr++;
00168        nn--;
00169     }
00170 
00171     /* remove certs with incorrect usage */
00172     rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
00173 
00174     if ( rv != SECSuccess ) {
00175        goto loser;
00176     }
00177 
00178     /* remove any extra certs for each name */
00179     if ( oneCertPerName ) {
00180        PRBool *flags;
00181 
00182        nn = nicknames->numnicknames;
00183        nnptr = nicknames->nicknames;
00184        
00185        flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn);
00186        if ( flags == NULL ) {
00187            goto loser;
00188        }
00189        
00190        node = CERT_LIST_HEAD(certList);
00191        
00192        /* treverse all certs in the list */
00193        while ( !CERT_LIST_END(node, certList) ) {
00194 
00195            /* find matching nickname index */
00196            for ( n = 0; n < nn; n++ ) {
00197               if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) {
00198                   /* We found a match.  If this is the first one, then
00199                    * set the flag and move on to the next cert.  If this
00200                    * is not the first one then delete it from the list.
00201                    */
00202                   if ( flags[n] ) {
00203                      /* We have already seen a cert with this nickname,
00204                       * so delete this one.
00205                       */
00206                      freenode = node;
00207                      node = CERT_LIST_NEXT(node);
00208                      CERT_RemoveCertListNode(freenode);
00209                   } else {
00210                      /* keep the first cert for each nickname, but set the
00211                       * flag so we know to delete any others with the same
00212                       * nickname.
00213                       */
00214                      flags[n] = PR_TRUE;
00215                      node = CERT_LIST_NEXT(node);
00216                   }
00217                   break;
00218               }
00219            }
00220            if ( n == nn ) {
00221               /* if we get here it means that we didn't find a matching
00222                * nickname, which should not happen.
00223                */
00224               PORT_Assert(0);
00225               node = CERT_LIST_NEXT(node);
00226            }
00227        }
00228        PORT_Free(flags);
00229     }
00230 
00231     goto done;
00232     
00233 loser:
00234     if ( certList != NULL ) {
00235        CERT_DestroyCertList(certList);
00236        certList = NULL;
00237     }
00238 
00239 done:
00240     if ( nicknames != NULL ) {
00241        CERT_FreeNicknames(nicknames);
00242     }
00243 
00244     return(certList);
00245 }
00246 
00247 /*
00248  * Find a user certificate that matchs the given criteria.
00249  * 
00250  *     "handle" - database to search
00251  *     "nickname" - nickname to match
00252  *     "usage" - certificate usage to match
00253  *     "validOnly" - only return certs that are curently valid
00254  *     "proto_win" - window handle passed to pkcs11
00255  */
00256 CERTCertificate *
00257 CERT_FindUserCertByUsage(CERTCertDBHandle *handle,
00258                       char *nickname,
00259                       SECCertUsage usage,
00260                       PRBool validOnly,
00261                       void *proto_win)
00262 {
00263     CERTCertificate *cert = NULL;
00264     CERTCertList *certList = NULL;
00265     SECStatus rv;
00266     int64 time;
00267     
00268     time = PR_Now();
00269     
00270     /* use the pk11 call so that we pick up any certs on tokens,
00271      * which may require login
00272      */
00273     /* XXX - why is this restricted? */
00274     if ( proto_win != NULL ) {
00275        cert = PK11_FindCertFromNickname(nickname,proto_win);
00276     }
00277 
00278 
00279     /* sigh, There are still problems find smart cards from the temp
00280      * db. This will get smart cards working again. The real fix
00281      * is to make sure we can search the temp db by their token nickname.
00282      */
00283     if (cert == NULL) {
00284        cert = CERT_FindCertByNickname(handle,nickname);
00285     }
00286 
00287     if ( cert != NULL ) {
00288        /* collect certs for this nickname, sorting them into the list */
00289        certList = CERT_CreateSubjectCertList(certList, handle, 
00290                                    &cert->derSubject, time, validOnly);
00291 
00292        CERT_FilterCertListForUserCerts(certList);
00293 
00294        /* drop the extra reference */
00295        CERT_DestroyCertificate(cert);
00296        cert = NULL;
00297     }
00298        
00299     if ( certList == NULL ) {
00300        goto loser;
00301     }
00302     
00303     /* remove certs with incorrect usage */
00304     rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
00305 
00306     if ( rv != SECSuccess ) {
00307        goto loser;
00308     }
00309 
00310     if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) {
00311        cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
00312     }
00313     
00314 loser:
00315     if ( certList != NULL ) {
00316        CERT_DestroyCertList(certList);
00317     }
00318 
00319     return(cert);
00320 }
00321 
00322 CERTCertList *
00323 CERT_MatchUserCert(CERTCertDBHandle *handle,
00324                  SECCertUsage usage,
00325                  int nCANames, char **caNames,
00326                  void *proto_win)
00327 {
00328     CERTCertList *certList = NULL;
00329     SECStatus rv;
00330 
00331     certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE,
00332                                     proto_win);
00333     if ( certList == NULL ) {
00334        goto loser;
00335     }
00336     
00337     rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage);
00338     if ( rv != SECSuccess ) {
00339        goto loser;
00340     }
00341     
00342     goto done;
00343     
00344 loser:
00345     if ( certList != NULL ) {
00346        CERT_DestroyCertList(certList);
00347        certList = NULL;
00348     }
00349 
00350 done:
00351 
00352     return(certList);
00353 }
00354 
00355 
00356 typedef struct stringNode {
00357     struct stringNode *next;
00358     char *string;
00359 } stringNode;
00360     
00361 static PRStatus
00362 CollectNicknames( NSSCertificate *c, void *data)
00363 {
00364     CERTCertNicknames *names;
00365     PRBool saveit = PR_FALSE;
00366     stringNode *node;
00367     int len;
00368 #ifdef notdef
00369     NSSTrustDomain *td;
00370     NSSTrust *trust;
00371 #endif
00372     char *stanNickname;
00373     char *nickname = NULL;
00374     
00375     names = (CERTCertNicknames *)data;
00376 
00377     stanNickname = nssCertificate_GetNickname(c,NULL);
00378     
00379     if ( stanNickname ) {
00380        if (names->what == SEC_CERT_NICKNAMES_USER) {
00381            saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL);
00382        }
00383 #ifdef notdef
00384          else {
00385            td = NSSCertificate_GetTrustDomain(c);
00386            if (!td) {
00387               return PR_SUCCESS;
00388            }
00389            trust = nssTrustDomain_FindTrustForCertificate(td,c);
00390        
00391            switch(names->what) {
00392             case SEC_CERT_NICKNAMES_ALL:
00393               if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
00394                (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
00395                (trust->objectSigningFlags & 
00396                                    (CERTDB_VALID_CA|CERTDB_VALID_PEER))) {
00397                   saveit = PR_TRUE;
00398               }
00399            
00400               break;
00401             case SEC_CERT_NICKNAMES_SERVER:
00402               if ( trust->sslFlags & CERTDB_VALID_PEER ) {
00403                   saveit = PR_TRUE;
00404               }
00405            
00406               break;
00407             case SEC_CERT_NICKNAMES_CA:
00408               if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)||
00409                ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) ||
00410                ((trust->objectSigningFlags & CERTDB_VALID_CA ) 
00411                                                  == CERTDB_VALID_CA)) {
00412                   saveit = PR_TRUE;
00413               }
00414               break;
00415            }
00416        }
00417 #endif
00418     }
00419 
00420     /* traverse the list of collected nicknames and make sure we don't make
00421      * a duplicate
00422      */
00423     if ( saveit ) {
00424        nickname = STAN_GetCERTCertificateName(NULL, c);
00425        /* nickname can only be NULL here if we are having memory 
00426         * alloc problems */
00427        if (nickname == NULL) {
00428            return PR_FAILURE;
00429        }
00430        node = (stringNode *)names->head;
00431        while ( node != NULL ) {
00432            if ( PORT_Strcmp(nickname, node->string) == 0 ) { 
00433               /* if the string matches, then don't save this one */
00434               saveit = PR_FALSE;
00435               break;
00436            }
00437            node = node->next;
00438        }
00439     }
00440 
00441     if ( saveit ) {
00442        
00443        /* allocate the node */
00444        node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
00445        if ( node == NULL ) {
00446            PORT_Free(nickname);
00447            return PR_FAILURE;
00448        }
00449 
00450        /* copy the string */
00451        len = PORT_Strlen(nickname) + 1;
00452        node->string = (char*)PORT_ArenaAlloc(names->arena, len);
00453        if ( node->string == NULL ) {
00454            PORT_Free(nickname);
00455            return PR_FAILURE;
00456        }
00457        PORT_Memcpy(node->string, nickname, len);
00458 
00459        /* link it into the list */
00460        node->next = (stringNode *)names->head;
00461        names->head = (void *)node;
00462 
00463        /* bump the count */
00464        names->numnicknames++;
00465     }
00466     
00467     if (nickname) PORT_Free(nickname);
00468     return(PR_SUCCESS);
00469 }
00470 
00471 CERTCertNicknames *
00472 CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
00473 {
00474     PRArenaPool *arena;
00475     CERTCertNicknames *names;
00476     int i;
00477     stringNode *node;
00478     
00479     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00480     if ( arena == NULL ) {
00481        PORT_SetError(SEC_ERROR_NO_MEMORY);
00482        return(NULL);
00483     }
00484     
00485     names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
00486     if ( names == NULL ) {
00487        goto loser;
00488     }
00489 
00490     names->arena = arena;
00491     names->head = NULL;
00492     names->numnicknames = 0;
00493     names->nicknames = NULL;
00494     names->what = what;
00495     names->totallen = 0;
00496 
00497     /* make sure we are logged in */
00498     (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
00499    
00500     NSSTrustDomain_TraverseCertificates(handle,
00501                                        CollectNicknames, (void *)names);
00502     if ( names->numnicknames ) {
00503        names->nicknames = (char**)PORT_ArenaAlloc(arena,
00504                                     names->numnicknames * sizeof(char *));
00505 
00506        if ( names->nicknames == NULL ) {
00507            goto loser;
00508        }
00509     
00510        node = (stringNode *)names->head;
00511        
00512        for ( i = 0; i < names->numnicknames; i++ ) {
00513            PORT_Assert(node != NULL);
00514            
00515            names->nicknames[i] = node->string;
00516            names->totallen += PORT_Strlen(node->string);
00517            node = node->next;
00518        }
00519 
00520        PORT_Assert(node == NULL);
00521     }
00522 
00523     return(names);
00524     
00525 loser:
00526     PORT_FreeArena(arena, PR_FALSE);
00527     return(NULL);
00528 }
00529 
00530 void
00531 CERT_FreeNicknames(CERTCertNicknames *nicknames)
00532 {
00533     PORT_FreeArena(nicknames->arena, PR_FALSE);
00534     
00535     return;
00536 }
00537 
00538 /* [ FROM pcertdb.c ] */
00539 
00540 typedef struct dnameNode {
00541     struct dnameNode *next;
00542     SECItem name;
00543 } dnameNode;
00544 
00545 void
00546 CERT_FreeDistNames(CERTDistNames *names)
00547 {
00548     PORT_FreeArena(names->arena, PR_FALSE);
00549     
00550     return;
00551 }
00552 
00553 static SECStatus
00554 CollectDistNames( CERTCertificate *cert, SECItem *k, void *data)
00555 {
00556     CERTDistNames *names;
00557     PRBool saveit = PR_FALSE;
00558     CERTCertTrust *trust;
00559     dnameNode *node;
00560     int len;
00561     
00562     names = (CERTDistNames *)data;
00563     
00564     if ( cert->trust ) {
00565        trust = cert->trust;
00566        
00567        /* only collect names of CAs trusted for issuing SSL clients */
00568        if (  trust->sslFlags &  CERTDB_TRUSTED_CLIENT_CA )  {
00569            saveit = PR_TRUE;
00570        }
00571     }
00572 
00573     if ( saveit ) {
00574        /* allocate the node */
00575        node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode));
00576        if ( node == NULL ) {
00577            return(SECFailure);
00578        }
00579 
00580        /* copy the name */
00581        node->name.len = len = cert->derSubject.len;
00582        node->name.type = siBuffer;
00583        node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len);
00584        if ( node->name.data == NULL ) {
00585            return(SECFailure);
00586        }
00587        PORT_Memcpy(node->name.data, cert->derSubject.data, len);
00588 
00589        /* link it into the list */
00590        node->next = (dnameNode *)names->head;
00591        names->head = (void *)node;
00592 
00593        /* bump the count */
00594        names->nnames++;
00595     }
00596     
00597     return(SECSuccess);
00598 }
00599 
00600 /*
00601  * Return all of the CAs that are "trusted" for SSL.
00602  */
00603 CERTDistNames *
00604 CERT_GetSSLCACerts(CERTCertDBHandle *handle)
00605 {
00606     PRArenaPool *arena;
00607     CERTDistNames *names;
00608     int i;
00609     SECStatus rv;
00610     dnameNode *node;
00611     
00612     /* allocate an arena to use */
00613     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00614     if ( arena == NULL ) {
00615        PORT_SetError(SEC_ERROR_NO_MEMORY);
00616        return(NULL);
00617     }
00618     
00619     /* allocate the header structure */
00620     names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
00621     if ( names == NULL ) {
00622        goto loser;
00623     }
00624 
00625     /* initialize the header struct */
00626     names->arena = arena;
00627     names->head = NULL;
00628     names->nnames = 0;
00629     names->names = NULL;
00630     
00631     /* collect the names from the database */
00632     rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL);
00633     if ( rv ) {
00634        goto loser;
00635     }
00636 
00637     /* construct the array from the list */
00638     if ( names->nnames ) {
00639        names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem));
00640 
00641        if ( names->names == NULL ) {
00642            goto loser;
00643        }
00644     
00645        node = (dnameNode *)names->head;
00646        
00647        for ( i = 0; i < names->nnames; i++ ) {
00648            PORT_Assert(node != NULL);
00649            
00650            names->names[i] = node->name;
00651            node = node->next;
00652        }
00653 
00654        PORT_Assert(node == NULL);
00655     }
00656 
00657     return(names);
00658     
00659 loser:
00660     PORT_FreeArena(arena, PR_FALSE);
00661     return(NULL);
00662 }
00663 
00664 CERTDistNames *
00665 CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
00666                         int nnames)
00667 {
00668     CERTDistNames *dnames = NULL;
00669     PRArenaPool *arena;
00670     int i, rv;
00671     SECItem *names = NULL;
00672     CERTCertificate *cert = NULL;
00673     
00674     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00675     if (arena == NULL) goto loser;
00676     dnames = PORT_ArenaZNew(arena, CERTDistNames);
00677     if (dnames == NULL) goto loser;
00678 
00679     dnames->arena = arena;
00680     dnames->nnames = nnames;
00681     dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
00682     if (names == NULL) goto loser;
00683     
00684     for (i = 0; i < nnames; i++) {
00685        cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]);
00686        if (cert == NULL) goto loser;
00687        rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject);
00688        if (rv == SECFailure) goto loser;
00689        CERT_DestroyCertificate(cert);
00690     }
00691     return dnames;
00692     
00693 loser:
00694     if (cert != NULL)
00695        CERT_DestroyCertificate(cert);
00696     if (arena != NULL)
00697        PORT_FreeArena(arena, PR_FALSE);
00698     return NULL;
00699 }
00700 
00701 /* [ from pcertdb.c - calls Ascii to Name ] */
00702 /*
00703  * Lookup a certificate in the database by name
00704  */
00705 CERTCertificate *
00706 CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
00707 {
00708     CERTName *name;
00709     SECItem *nameItem;
00710     CERTCertificate *cert = NULL;
00711     PRArenaPool *arena = NULL;
00712     
00713     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00714     
00715     if ( arena == NULL ) {
00716        goto loser;
00717     }
00718     
00719     name = CERT_AsciiToName(nameStr);
00720     
00721     if ( name ) {
00722        nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name,
00723                                    CERT_NameTemplate);
00724        if ( nameItem != NULL ) {
00725             cert = CERT_FindCertByName(handle, nameItem);
00726        }
00727        CERT_DestroyName(name);
00728     }
00729 
00730 loser:
00731     if ( arena ) {
00732        PORT_FreeArena(arena, PR_FALSE);
00733     }
00734     
00735     return(cert);
00736 }
00737 
00738 /* From certv3.c */
00739 
00740 CERTCrlDistributionPoints *
00741 CERT_FindCRLDistributionPoints (CERTCertificate *cert)
00742 {
00743     SECItem encodedExtenValue;
00744     SECStatus rv;
00745     CERTCrlDistributionPoints *dps;
00746 
00747     encodedExtenValue.data = NULL;
00748     encodedExtenValue.len = 0;
00749 
00750     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS,
00751                          &encodedExtenValue);
00752     if ( rv != SECSuccess ) {
00753        return (NULL);
00754     }
00755 
00756     dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue);
00757 
00758     PORT_Free(encodedExtenValue.data);
00759 
00760     return dps;
00761 }
00762 
00763 /* From crl.c */
00764 CERTSignedCrl * CERT_ImportCRL
00765    (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx)
00766 {
00767     CERTSignedCrl* retCrl = NULL;
00768     PK11SlotInfo* slot = PK11_GetInternalKeySlot();
00769     retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx,
00770         CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
00771     PK11_FreeSlot(slot);
00772 
00773     return retCrl;
00774 }
00775 
00776 /* From certdb.c */
00777 static SECStatus
00778 cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted)
00779 {
00780     SECStatus rv;
00781     SECItem *derCert;
00782     CERTCertificate *cert = NULL;
00783     CERTCertificate *newcert = NULL;
00784     CERTCertDBHandle *handle;
00785     CERTCertTrust trust;
00786     PRBool isca;
00787     char *nickname;
00788     unsigned int certtype;
00789     
00790     handle = CERT_GetDefaultCertDB();
00791     
00792     while (numcerts--) {
00793        derCert = certs;
00794        certs++;
00795 
00796        /* decode my certificate */
00797        /* This use is ok -- only looks at decoded parts, calls NewTemp later */
00798        newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
00799        if ( newcert == NULL ) {
00800            goto loser;
00801        }
00802 
00803        if (!trusted) {
00804            /* make sure that cert is valid */
00805            rv = CERT_CertTimesValid(newcert);
00806            if ( rv == SECFailure ) {
00807               goto endloop;
00808            }
00809        }
00810 
00811        /* does it have the CA extension */
00812        
00813        /*
00814         * Make sure that if this is an intermediate CA in the chain that
00815         * it was given permission by its signer to be a CA.
00816         */
00817        isca = CERT_IsCACert(newcert, &certtype);
00818 
00819        if ( !isca ) {
00820            if (!trusted) {
00821               goto endloop;
00822            }
00823            trust.sslFlags = CERTDB_VALID_CA;
00824            trust.emailFlags = CERTDB_VALID_CA;
00825            trust.objectSigningFlags = CERTDB_VALID_CA;
00826        } else {
00827            /* SSL ca's must have the ssl bit set */
00828            if ( ( certUsage == certUsageSSLCA ) &&
00829               (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) {
00830               goto endloop;
00831            }
00832 
00833            /* it passed all of the tests, so lets add it to the database */
00834            /* mark it as a CA */
00835            PORT_Memset((void *)&trust, 0, sizeof(trust));
00836            switch ( certUsage ) {
00837              case certUsageSSLCA:
00838               trust.sslFlags = CERTDB_VALID_CA;
00839               break;
00840              case certUsageUserCertImport:
00841               if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
00842                   trust.sslFlags = CERTDB_VALID_CA;
00843               }
00844               if ((certtype & NS_CERT_TYPE_EMAIL_CA) 
00845                                           == NS_CERT_TYPE_EMAIL_CA ) {
00846                   trust.emailFlags = CERTDB_VALID_CA;
00847               }
00848               if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) ==
00849                                    NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
00850                    trust.objectSigningFlags = CERTDB_VALID_CA;
00851               }
00852               break;
00853              default:
00854               PORT_Assert(0);
00855               break;
00856            }
00857        }
00858        
00859        cert = CERT_NewTempCertificate(handle, derCert, NULL, 
00860                                                  PR_FALSE, PR_FALSE);
00861        if ( cert == NULL ) {
00862            goto loser;
00863        }
00864        
00865        /* if the cert is temp, make it perm; otherwise we're done */
00866        if (cert->istemp) {
00867            /* get a default nickname for it */
00868            nickname = CERT_MakeCANickname(cert);
00869 
00870            rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
00871 
00872            /* free the nickname */
00873            if ( nickname ) {
00874               PORT_Free(nickname);
00875            }
00876        } else {
00877            rv = SECSuccess;
00878        }
00879 
00880        CERT_DestroyCertificate(cert);
00881        cert = NULL;
00882        
00883        if ( rv != SECSuccess ) {
00884            goto loser;
00885        }
00886 
00887 endloop:
00888        if ( newcert ) {
00889            CERT_DestroyCertificate(newcert);
00890            newcert = NULL;
00891        }
00892        
00893     }
00894 
00895     rv = SECSuccess;
00896     goto done;
00897 loser:
00898     rv = SECFailure;
00899 done:
00900     
00901     if ( newcert ) {
00902        CERT_DestroyCertificate(newcert);
00903        newcert = NULL;
00904     }
00905     
00906     if ( cert ) {
00907        CERT_DestroyCertificate(cert);
00908        cert = NULL;
00909     }
00910     
00911     return(rv);
00912 }
00913 
00914 SECStatus
00915 CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage)
00916 {
00917     return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE);
00918 }
00919 
00920 SECStatus
00921 CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) {
00922     return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE);
00923 }
00924 
00925 /* Moved from certdb.c */
00926 /*
00927 ** CERT_CertChainFromCert
00928 **
00929 ** Construct a CERTCertificateList consisting of the given certificate and all
00930 ** of the issuer certs until we either get to a self-signed cert or can't find
00931 ** an issuer.  Since we don't know how many certs are in the chain we have to
00932 ** build a linked list first as we count them.
00933 */
00934 
00935 typedef struct certNode {
00936     struct certNode *next;
00937     CERTCertificate *cert;
00938 } certNode;
00939 
00940 CERTCertificateList *
00941 CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
00942                      PRBool includeRoot)
00943 {
00944 #ifdef NSS_CLASSIC
00945     CERTCertificateList *chain = NULL;
00946     CERTCertificate *c;
00947     SECItem *p;
00948     int rv, len = 0;
00949     PRArenaPool *tmpArena, *arena;
00950     certNode *head, *tail, *node;
00951 
00952     /*
00953      * Initialize stuff so we can goto loser.
00954      */
00955     head = NULL;
00956     arena = NULL;
00957 
00958     /* arena for linked list */
00959     tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00960     if (tmpArena == NULL) goto no_memory;
00961 
00962     /* arena for SecCertificateList */
00963     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00964     if (arena == NULL) goto no_memory;
00965 
00966     head = tail = (certNode*)PORT_ArenaZAlloc(tmpArena, sizeof(certNode));
00967     if (head == NULL) goto no_memory;
00968 
00969     /* put primary cert first in the linked list */
00970     head->cert = c = CERT_DupCertificate(cert);
00971     if (head->cert == NULL) goto loser;
00972     len++;
00973 
00974     /* add certs until we come to a self-signed one */
00975     while(SECITEM_CompareItem(&c->derIssuer, &c->derSubject) != SECEqual) {
00976        c = CERT_FindCertIssuer(tail->cert, PR_Now(), usage);
00977        if (c == NULL) {
00978            /* no root is found, so make sure we don't attempt to delete one
00979             * below
00980             */
00981            includeRoot = PR_TRUE;
00982            break;
00983        }
00984        
00985        tail->next = (certNode*)PORT_ArenaZAlloc(tmpArena, sizeof(certNode));
00986        tail = tail->next;
00987        if (tail == NULL) goto no_memory;
00988        
00989        tail->cert = c;
00990        len++;
00991     }
00992 
00993     /* now build the CERTCertificateList */
00994     chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
00995     if (chain == NULL) goto no_memory;
00996     chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
00997     if (chain->certs == NULL) goto no_memory;
00998     
00999     for(node = head, p = chain->certs; node; node = node->next, p++) {
01000        rv = SECITEM_CopyItem(arena, p, &node->cert->derCert);
01001        CERT_DestroyCertificate(node->cert);
01002        node->cert = NULL;
01003        if (rv < 0) goto loser;
01004     }
01005     if ( !includeRoot && len > 1) {
01006        chain->len = len - 1;
01007     } else {
01008        chain->len = len;
01009     }
01010     
01011     chain->arena = arena;
01012 
01013     PORT_FreeArena(tmpArena, PR_FALSE);
01014     
01015     return chain;
01016 
01017 no_memory:
01018     PORT_SetError(SEC_ERROR_NO_MEMORY);
01019 loser:
01020     if (head != NULL) {
01021        for (node = head; node; node = node->next) {
01022            if (node->cert != NULL)
01023               CERT_DestroyCertificate(node->cert);
01024        }
01025     }
01026 
01027     if (arena != NULL) {
01028        PORT_FreeArena(arena, PR_FALSE);
01029     }
01030 
01031     if (tmpArena != NULL) {
01032        PORT_FreeArena(tmpArena, PR_FALSE);
01033     }
01034 
01035     return NULL;
01036 #else
01037     CERTCertificateList *chain = NULL;
01038     NSSCertificate **stanChain;
01039     NSSCertificate *stanCert;
01040     PRArenaPool *arena;
01041     NSSUsage nssUsage;
01042     int i, len;
01043     NSSTrustDomain *td   = STAN_GetDefaultTrustDomain();
01044     NSSCryptoContext *cc = STAN_GetDefaultCryptoContext();
01045 
01046     stanCert = STAN_GetNSSCertificate(cert);
01047     nssUsage.anyUsage = PR_FALSE;
01048     nssUsage.nss3usage = usage;
01049     nssUsage.nss3lookingForCA = PR_FALSE;
01050     stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL,
01051                                      NULL, 0, NULL, NULL, td, cc);
01052     if (!stanChain) {
01053        PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
01054        return NULL;
01055     }
01056 
01057     len = 0;
01058     stanCert = stanChain[0];
01059     while (stanCert) {
01060        stanCert = stanChain[++len];
01061     }
01062 
01063     arena = PORT_NewArena(4096);
01064     if (arena == NULL) {
01065        goto loser;
01066     }
01067 
01068     chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, 
01069                                                  sizeof(CERTCertificateList));
01070     if (!chain) goto loser;
01071     chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
01072     if (!chain->certs) goto loser;
01073     i = 0;
01074     stanCert = stanChain[i];
01075     while (stanCert) {
01076        SECItem derCert;
01077        CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
01078        if (!cCert) {
01079            goto loser;
01080        }
01081        derCert.len = (unsigned int)stanCert->encoding.size;
01082        derCert.data = (unsigned char *)stanCert->encoding.data;
01083        derCert.type = siBuffer;
01084        SECITEM_CopyItem(arena, &chain->certs[i], &derCert);
01085        stanCert = stanChain[++i];
01086        if (!stanCert && !cCert->isRoot) {
01087            /* reached the end of the chain, but the final cert is
01088             * not a root.  Don't discard it.
01089             */
01090            includeRoot = PR_TRUE;
01091        }
01092        CERT_DestroyCertificate(cCert);
01093     }
01094     if ( !includeRoot && len > 1) {
01095        chain->len = len - 1;
01096     } else {
01097        chain->len = len;
01098     }
01099     
01100     chain->arena = arena;
01101     nss_ZFreeIf(stanChain);
01102     return chain;
01103 loser:
01104     i = 0;
01105     stanCert = stanChain[i];
01106     while (stanCert) {
01107        CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
01108        if (cCert) {
01109            CERT_DestroyCertificate(cCert);
01110        }
01111        stanCert = stanChain[++i];
01112     }
01113     nss_ZFreeIf(stanChain);
01114     if (arena) {
01115        PORT_FreeArena(arena, PR_FALSE);
01116     }
01117     return NULL;
01118 #endif
01119 }
01120 
01121 /* Builds a CERTCertificateList holding just one DER-encoded cert, namely
01122 ** the one for the cert passed as an argument.
01123 */
01124 CERTCertificateList *
01125 CERT_CertListFromCert(CERTCertificate *cert)
01126 {
01127     CERTCertificateList *chain = NULL;
01128     int rv;
01129     PRArenaPool *arena;
01130 
01131     /* arena for SecCertificateList */
01132     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01133     if (arena == NULL) goto no_memory;
01134 
01135     /* build the CERTCertificateList */
01136     chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
01137     if (chain == NULL) goto no_memory;
01138     chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem));
01139     if (chain->certs == NULL) goto no_memory;
01140     rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert));
01141     if (rv < 0) goto loser;
01142     chain->len = 1;
01143     chain->arena = arena;
01144 
01145     return chain;
01146 
01147 no_memory:
01148     PORT_SetError(SEC_ERROR_NO_MEMORY);
01149 loser:
01150     if (arena != NULL) {
01151        PORT_FreeArena(arena, PR_FALSE);
01152     }
01153     return NULL;
01154 }
01155 
01156 CERTCertificateList *
01157 CERT_DupCertList(CERTCertificateList * oldList)
01158 {
01159     CERTCertificateList *newList = NULL;
01160     PRArenaPool         *arena   = NULL;
01161     SECItem             *newItem;
01162     SECItem             *oldItem;
01163     int                 len      = oldList->len;
01164     int                 rv;
01165 
01166     /* arena for SecCertificateList */
01167     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01168     if (arena == NULL) 
01169        goto no_memory;
01170 
01171     /* now build the CERTCertificateList */
01172     newList = PORT_ArenaNew(arena, CERTCertificateList);
01173     if (newList == NULL) 
01174        goto no_memory;
01175     newList->arena = arena;
01176     newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
01177     if (newItem == NULL) 
01178        goto no_memory;
01179     newList->certs = newItem;
01180     newList->len   = len;
01181 
01182     for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) {
01183        rv = SECITEM_CopyItem(arena, newItem, oldItem);
01184        if (rv < 0) 
01185            goto loser;
01186     }
01187     return newList;
01188 
01189 no_memory:
01190     PORT_SetError(SEC_ERROR_NO_MEMORY);
01191 loser:
01192     if (arena != NULL) {
01193        PORT_FreeArena(arena, PR_FALSE);
01194     }
01195     return NULL;
01196 }
01197 
01198 void
01199 CERT_DestroyCertificateList(CERTCertificateList *list)
01200 {
01201     PORT_FreeArena(list->arena, PR_FALSE);
01202 }
01203