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