Back to index

lightning-sunbird  0.9+nobinonly
pk11cert.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  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  * This file manages PKCS #11 instances of certificates.
00039  */
00040 
00041 #include "secport.h"
00042 #include "seccomon.h"
00043 #include "secmod.h"
00044 #include "secmodi.h"
00045 #include "secmodti.h"
00046 #include "pkcs11.h"
00047 #include "pk11func.h"
00048 #include "cert.h"
00049 #include "certi.h"
00050 #include "secitem.h"
00051 #include "key.h" 
00052 #include "secoid.h"
00053 #include "pkcs7t.h"
00054 #include "cmsreclist.h"
00055 
00056 #include "certdb.h"
00057 #include "secerr.h"
00058 #include "sslerr.h"
00059 
00060 #include "pki3hack.h"
00061 #include "dev3hack.h"
00062 
00063 #include "devm.h" 
00064 #include "nsspki.h"
00065 #include "pki.h"
00066 #include "pkim.h"
00067 #include "pkitm.h"
00068 #include "pkistore.h" /* to remove temp cert */
00069 #include "devt.h"
00070 
00071 extern const NSSError NSS_ERROR_NOT_FOUND;
00072 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
00073 
00074 struct nss3_cert_cbstr {
00075     SECStatus(* callback)(CERTCertificate*, void *);
00076     nssList *cached;
00077     void *arg;
00078 };
00079 
00080 /* Translate from NSSCertificate to CERTCertificate, then pass the latter
00081  * to a callback.
00082  */
00083 static PRStatus convert_cert(NSSCertificate *c, void *arg)
00084 {
00085     CERTCertificate *nss3cert;
00086     SECStatus secrv;
00087     struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
00088     /* 'c' is not adopted. caller will free it */
00089     nss3cert = STAN_GetCERTCertificate(c);
00090     if (!nss3cert) return PR_FAILURE;
00091     secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg);
00092     return (secrv) ? PR_FAILURE : PR_SUCCESS;
00093 }
00094 
00095 /*
00096  * build a cert nickname based on the token name and the label of the 
00097  * certificate If the label in NULL, build a label based on the ID.
00098  */
00099 static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); }
00100 #define MAX_CERT_ID 4
00101 #define DEFAULT_STRING "Cert ID "
00102 static char *
00103 pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label,
00104                      CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
00105 {
00106     int prefixLen = PORT_Strlen(slot->token_name);
00107     int suffixLen = 0;
00108     char *suffix = NULL;
00109     char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2];
00110     char *next,*nickname;
00111 
00112     if (cert_label && (cert_label->ulValueLen)) {
00113        suffixLen = cert_label->ulValueLen;
00114        suffix = (char*)cert_label->pValue;
00115     } else if (key_label && (key_label->ulValueLen)) {
00116        suffixLen = key_label->ulValueLen;
00117        suffix = (char*)key_label->pValue;
00118     } else if (cert_id && cert_id->ulValueLen > 0) {
00119        int i,first = cert_id->ulValueLen - MAX_CERT_ID;
00120        int offset = sizeof(DEFAULT_STRING);
00121        char *idValue = (char *)cert_id->pValue;
00122 
00123        PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1);
00124        next = buildNew + offset;
00125        if (first < 0) first = 0;
00126        for (i=first; i < (int) cert_id->ulValueLen; i++) {
00127               *next++ = toHex((idValue[i] >> 4) & 0xf);
00128               *next++ = toHex(idValue[i] & 0xf);
00129        }
00130        *next++ = 0;
00131        suffix = buildNew;
00132        suffixLen = PORT_Strlen(buildNew);
00133     } else {
00134        PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );
00135        return NULL;
00136     }
00137 
00138     /* if is internal key slot, add code to skip the prefix!! */
00139     next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1);
00140     if (nickname == NULL) return NULL;
00141 
00142     PORT_Memcpy(next,slot->token_name,prefixLen);
00143     next += prefixLen;
00144     *next++ = ':';
00145     PORT_Memcpy(next,suffix,suffixLen);
00146     next += suffixLen;
00147     *next++ = 0;
00148     return nickname;
00149 }
00150 
00151 PRBool
00152 PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
00153                                           CK_OBJECT_HANDLE certID)
00154 {
00155     CK_OBJECT_CLASS theClass;
00156 
00157     if (slot == NULL) return PR_FALSE;
00158     if (cert == NULL) return PR_FALSE;
00159 
00160     theClass = CKO_PRIVATE_KEY;
00161     if (pk11_LoginStillRequired(slot,NULL)) {
00162        theClass = CKO_PUBLIC_KEY;
00163     }
00164     if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_HANDLE) {
00165        return PR_TRUE;
00166     }
00167 
00168    if (theClass == CKO_PUBLIC_KEY) {
00169        SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert);
00170        CK_ATTRIBUTE theTemplate;
00171 
00172        if (pubKey == NULL) {
00173           return PR_FALSE;
00174        }
00175 
00176        PK11_SETATTRS(&theTemplate,0,NULL,0);
00177        switch (pubKey->keyType) {
00178        case rsaKey:
00179            PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data,
00180                                           pubKey->u.rsa.modulus.len);
00181            break;
00182        case dsaKey:
00183            PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data,
00184                                           pubKey->u.dsa.publicValue.len);
00185            break;
00186        case dhKey:
00187            PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data,
00188                                           pubKey->u.dh.publicValue.len);
00189            break;
00190        case ecKey:
00191            PK11_SETATTRS(&theTemplate,CKA_EC_POINT, 
00192                        pubKey->u.ec.publicValue.data,
00193                        pubKey->u.ec.publicValue.len);
00194            break;
00195        case keaKey:
00196        case fortezzaKey:
00197        case nullKey:
00198            /* fall through and return false */
00199            break;
00200        }
00201 
00202        if (theTemplate.ulValueLen == 0) {
00203            SECKEY_DestroyPublicKey(pubKey);
00204            return PR_FALSE;
00205        }
00206        pk11_SignedToUnsigned(&theTemplate);
00207        if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_HANDLE) {
00208            SECKEY_DestroyPublicKey(pubKey);
00209            return PR_TRUE;
00210        }
00211        SECKEY_DestroyPublicKey(pubKey);
00212     }
00213     return PR_FALSE;
00214 }
00215 
00216 /*
00217  * Check out if a cert has ID of zero. This is a magic ID that tells
00218  * NSS that this cert may be an automagically trusted cert.
00219  * The Cert has to be self signed as well. That check is done elsewhere.
00220  *  
00221  */
00222 PRBool
00223 pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
00224 {
00225     CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0};
00226     PRBool isZero = PR_FALSE;
00227     int i;
00228     CK_RV crv;
00229 
00230 
00231     crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1);
00232     if (crv != CKR_OK) {
00233        return isZero;
00234     }
00235 
00236     if (keyID.ulValueLen != 0) {
00237        char *value = (char *)keyID.pValue;
00238        isZero = PR_TRUE; /* ID exists, may be zero */
00239        for (i=0; i < (int) keyID.ulValueLen; i++) {
00240            if (value[i] != 0) {
00241               isZero = PR_FALSE; /* nope */
00242               break;
00243            }
00244        }
00245     }
00246     PORT_Free(keyID.pValue);
00247     return isZero;
00248 
00249 }
00250 
00251 /*
00252  * Create an NSSCertificate from a slot/certID pair, return it as a
00253  * CERTCertificate.
00254  */
00255 static CERTCertificate
00256 *pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, 
00257                      CK_ATTRIBUTE *privateLabel, char **nickptr)
00258 {
00259     NSSCertificate *c;
00260     nssCryptokiObject *co;
00261     nssPKIObject *pkio;
00262     NSSToken *token;
00263     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
00264 
00265     /* Get the cryptoki object from the handle */
00266     token = PK11Slot_GetNSSToken(slot);
00267     co = nssCryptokiObject_Create(token, token->defaultSession, certID);
00268     if (!co) {
00269        return NULL;
00270     }
00271 
00272     /* Create a PKI object from the cryptoki instance */
00273     pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor);
00274     if (!pkio) {
00275        nssCryptokiObject_Destroy(co);
00276        return NULL;
00277     }
00278 
00279     /* Create a certificate */
00280     c = nssCertificate_Create(pkio);
00281     if (!c) {
00282        nssPKIObject_Destroy(pkio);
00283        return NULL;
00284     }
00285 
00286     nssTrustDomain_AddCertsToCache(td, &c, 1);
00287 
00288     /* Build the old-fashioned nickname */
00289     if ((nickptr) && (co->label)) {
00290        CK_ATTRIBUTE label, id;
00291        label.type = CKA_LABEL;
00292        label.pValue = co->label;
00293        label.ulValueLen = PORT_Strlen(co->label);
00294        id.type = CKA_ID;
00295        id.pValue = c->id.data;
00296        id.ulValueLen = c->id.size;
00297        *nickptr = pk11_buildNickname(slot, &label, privateLabel, &id);
00298     }
00299     return STAN_GetCERTCertificateOrRelease(c);
00300 }
00301 
00302 /*
00303  * Build an CERTCertificate structure from a PKCS#11 object ID.... certID
00304  * Must be a CertObject. This code does not explicitly checks that.
00305  */
00306 CERTCertificate *
00307 PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID,
00308                                           CK_ATTRIBUTE *privateLabel)
00309 {
00310     char * nickname = NULL;
00311     CERTCertificate *cert = NULL;
00312     CERTCertTrust *trust;
00313     PRBool isFortezzaRootCA = PR_FALSE;
00314     PRBool swapNickname = PR_FALSE;
00315 
00316     cert = pk11_fastCert(slot,certID,privateLabel, &nickname);
00317     if (cert == NULL) goto loser;
00318        
00319     if (nickname) {
00320        if (cert->nickname != NULL) {
00321               cert->dbnickname = cert->nickname;
00322        } 
00323        cert->nickname = PORT_ArenaStrdup(cert->arena,nickname);
00324        PORT_Free(nickname);
00325        nickname = NULL;
00326        swapNickname = PR_TRUE;
00327     }
00328 
00329     /* remember where this cert came from.... If we have just looked
00330      * it up from the database and it already has a slot, don't add a new
00331      * one. */
00332     if (cert->slot == NULL) {
00333        cert->slot = PK11_ReferenceSlot(slot);
00334        cert->pkcs11ID = certID;
00335        cert->ownSlot = PR_TRUE;
00336        cert->series = slot->series;
00337     }
00338 
00339     trust = (CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
00340     if (trust == NULL) goto loser;
00341     PORT_Memset(trust,0, sizeof(CERTCertTrust));
00342     cert->trust = trust;
00343 
00344     
00345 
00346     if(! pk11_HandleTrustObject(slot, cert, trust) ) {
00347        unsigned int type;
00348 
00349        /* build some cert trust flags */
00350        if (CERT_IsCACert(cert, &type)) {
00351            unsigned int trustflags = CERTDB_VALID_CA;
00352           
00353            /* Allow PKCS #11 modules to give us trusted CA's. We only accept
00354             * valid CA's which are self-signed here. They must have an object
00355             * ID of '0'.  */ 
00356            if (pk11_isID0(slot,certID) && 
00357               SECITEM_CompareItem(&cert->derSubject,&cert->derIssuer)
00358                                                     == SECEqual) {
00359               trustflags |= CERTDB_TRUSTED_CA;
00360               /* is the slot a fortezza card? allow the user or
00361                * admin to turn on objectSigning, but don't turn
00362                * full trust on explicitly */
00363               if (PK11_DoesMechanism(slot,CKM_KEA_KEY_DERIVE)) {
00364                   trust->objectSigningFlags |= CERTDB_VALID_CA;
00365                   isFortezzaRootCA = PR_TRUE;
00366               }
00367            }
00368            if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
00369               trust->sslFlags |= trustflags;
00370            }
00371            if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
00372               trust->emailFlags |= trustflags;
00373            }
00374            if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) 
00375                                    == NS_CERT_TYPE_OBJECT_SIGNING_CA) {
00376               trust->objectSigningFlags |= trustflags;
00377            }
00378        }
00379     }
00380 
00381     if (PK11_IsUserCert(slot,cert,certID)) {
00382        trust->sslFlags |= CERTDB_USER;
00383        trust->emailFlags |= CERTDB_USER;
00384        /*    trust->objectSigningFlags |= CERTDB_USER; */
00385     }
00386 
00387     return cert;
00388 
00389 loser:
00390     if (nickname) PORT_Free(nickname);
00391     if (cert) CERT_DestroyCertificate(cert);
00392     return NULL;
00393 }
00394 
00395        
00396 /*
00397  * Build get a certificate from a private key
00398  */
00399 CERTCertificate *
00400 PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
00401 {
00402     PK11SlotInfo *slot = privKey->pkcs11Slot;
00403     CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
00404     CK_OBJECT_HANDLE certID = 
00405               PK11_MatchItem(slot,handle,CKO_CERTIFICATE);
00406     CERTCertificate *cert;
00407 
00408     if (certID == CK_INVALID_HANDLE) {
00409        PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
00410        return NULL;
00411     }
00412     cert = PK11_MakeCertFromHandle(slot,certID,NULL);
00413     return (cert);
00414 
00415 }
00416 
00417 /*
00418  * delete a cert and it's private key (if no other certs are pointing to the
00419  * private key.
00420  */
00421 SECStatus
00422 PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx)
00423 {
00424     SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert,wincx);
00425     CK_OBJECT_HANDLE pubKey;
00426     PK11SlotInfo *slot = NULL;
00427 
00428     pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
00429     if (privKey) {
00430        /* For 3.4, utilize the generic cert delete function */
00431        SEC_DeletePermCertificate(cert);
00432        PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
00433     }
00434     if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) { 
00435        PK11_DestroyTokenObject(slot,pubKey);
00436         PK11_FreeSlot(slot);
00437     }
00438     return SECSuccess;
00439 }
00440 
00441 /*
00442  * cert callback structure
00443  */
00444 typedef struct pk11DoCertCallbackStr {
00445        SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *);
00446        SECStatus(* noslotcallback)(CERTCertificate*, void *);
00447        SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *);
00448        void *callbackArg;
00449 } pk11DoCertCallback;
00450 
00451 
00452 typedef struct pk11CertCallbackStr {
00453        SECStatus(* callback)(CERTCertificate*,SECItem *,void *);
00454        void *callbackArg;
00455 } pk11CertCallback;
00456 
00457 struct fake_der_cb_argstr
00458 {
00459     SECStatus(* callback)(CERTCertificate*, SECItem *, void *);
00460     void *arg;
00461 };
00462 
00463 static SECStatus fake_der_cb(CERTCertificate *c, void *a)
00464 {
00465     struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
00466     return (*fda->callback)(c, &c->derCert, fda->arg);
00467 }
00468 
00469 /*
00470  * Extract all the certs on a card from a slot.
00471  */
00472 SECStatus
00473 PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
00474                                           void *arg, void *wincx) 
00475 {
00476     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
00477     struct fake_der_cb_argstr fda;
00478     struct nss3_cert_cbstr pk11cb;
00479 
00480     /* authenticate to the tokens first */
00481     (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, wincx);
00482 
00483     fda.callback = callback;
00484     fda.arg = arg;
00485     pk11cb.callback = fake_der_cb;
00486     pk11cb.arg = &fda;
00487     NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
00488     return SECSuccess;
00489 }
00490 
00491 static void
00492 transfer_token_certs_to_collection(nssList *certList, NSSToken *token, 
00493                                    nssPKIObjectCollection *collection)
00494 {
00495     NSSCertificate **certs;
00496     PRUint32 i, count;
00497     NSSToken **tokens, **tp;
00498     count = nssList_Count(certList);
00499     if (count == 0) {
00500        return;
00501     }
00502     certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
00503     if (!certs) {
00504        return;
00505     }
00506     nssList_GetArray(certList, (void **)certs, count);
00507     for (i=0; i<count; i++) {
00508        tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
00509        if (tokens) {
00510            for (tp = tokens; *tp; tp++) {
00511               if (*tp == token) {
00512                   nssPKIObjectCollection_AddObject(collection, 
00513                                                    (nssPKIObject *)certs[i]);
00514               }
00515            }
00516            nssTokenArray_Destroy(tokens);
00517        }
00518        CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
00519     }
00520     nss_ZFreeIf(certs);
00521 }
00522 
00523 CERTCertificate *
00524 PK11_FindCertFromNickname(char *nickname, void *wincx) 
00525 {
00526     PRStatus status;
00527     CERTCertificate *rvCert = NULL;
00528     NSSCertificate *cert = NULL;
00529     NSSCertificate **certs = NULL;
00530     static const NSSUsage usage = {PR_TRUE /* ... */ };
00531     NSSToken *token;
00532     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
00533     PK11SlotInfo *slot = NULL;
00534     SECStatus rv;
00535     char *nickCopy;
00536     char *delimit = NULL;
00537     char *tokenName;
00538 
00539     nickCopy = PORT_Strdup(nickname);
00540     if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
00541        tokenName = nickCopy;
00542        nickname = delimit + 1;
00543        *delimit = '\0';
00544        /* find token by name */
00545        token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
00546        if (token) {
00547            slot = PK11_ReferenceSlot(token->pk11slot);
00548        } else {
00549            PORT_SetError(SEC_ERROR_NO_TOKEN);
00550        }
00551        *delimit = ':';
00552     } else {
00553        slot = PK11_GetInternalKeySlot();
00554        token = PK11Slot_GetNSSToken(slot);
00555     }
00556     if (token) {
00557        nssList *certList;
00558        nssCryptokiObject **instances;
00559        nssPKIObjectCollection *collection;
00560        nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
00561        if (!PK11_IsPresent(slot)) {
00562            goto loser;
00563        }
00564        rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
00565        if (rv != SECSuccess) {
00566            goto loser;
00567        }
00568        collection = nssCertificateCollection_Create(defaultTD, NULL);
00569        if (!collection) {
00570            goto loser;
00571        }
00572        certList = nssList_Create(NULL, PR_FALSE);
00573        if (!certList) {
00574            nssPKIObjectCollection_Destroy(collection);
00575            goto loser;
00576        }
00577        (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, 
00578                                                          nickname, 
00579                                                          certList);
00580        transfer_token_certs_to_collection(certList, token, collection);
00581        instances = nssToken_FindCertificatesByNickname(token,
00582                                                        NULL,
00583                                                        nickname,
00584                                                        tokenOnly,
00585                                                        0,
00586                                                        &status);
00587        nssPKIObjectCollection_AddInstances(collection, instances, 0);
00588        nss_ZFreeIf(instances);
00589        /* if it wasn't found, repeat the process for email address */
00590        if (nssPKIObjectCollection_Count(collection) == 0 &&
00591            PORT_Strchr(nickname, '@') != NULL) 
00592        {
00593            char* lowercaseName = CERT_FixupEmailAddr(nickname);
00594            if (lowercaseName) {
00595               (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 
00596                                                               lowercaseName, 
00597                                                               certList);
00598               transfer_token_certs_to_collection(certList, token, collection);
00599               instances = nssToken_FindCertificatesByEmail(token,
00600                                                       NULL,
00601                                                       lowercaseName,
00602                                                       tokenOnly,
00603                                                       0,
00604                                                       &status);
00605               nssPKIObjectCollection_AddInstances(collection, instances, 0);
00606               nss_ZFreeIf(instances);
00607               PORT_Free(lowercaseName);
00608            }
00609        }
00610        certs = nssPKIObjectCollection_GetCertificates(collection, 
00611                                                       NULL, 0, NULL);
00612        nssPKIObjectCollection_Destroy(collection);
00613        if (certs) {
00614            cert = nssCertificateArray_FindBestCertificate(certs, NULL, 
00615                                                           &usage, NULL);
00616            if (cert) {
00617               rvCert = STAN_GetCERTCertificateOrRelease(cert);
00618            }
00619            nssCertificateArray_Destroy(certs);
00620        }
00621        nssList_Destroy(certList);
00622     }
00623     if (slot) {
00624        PK11_FreeSlot(slot);
00625     }
00626     if (nickCopy) PORT_Free(nickCopy);
00627     return rvCert;
00628 loser:
00629     if (slot) {
00630        PK11_FreeSlot(slot);
00631     }
00632     if (nickCopy) PORT_Free(nickCopy);
00633     return NULL;
00634 }
00635 
00636 CERTCertList *
00637 PK11_FindCertsFromNickname(char *nickname, void *wincx) 
00638 {
00639     char *nickCopy;
00640     char *delimit = NULL;
00641     char *tokenName;
00642     int i;
00643     CERTCertList *certList = NULL;
00644     nssPKIObjectCollection *collection = NULL;
00645     NSSCertificate **foundCerts = NULL;
00646     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
00647     NSSCertificate *c;
00648     NSSToken *token;
00649     PK11SlotInfo *slot;
00650     SECStatus rv;
00651 
00652     nickCopy = PORT_Strdup(nickname);
00653     if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
00654        tokenName = nickCopy;
00655        nickname = delimit + 1;
00656        *delimit = '\0';
00657        /* find token by name */
00658        token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
00659        if (token) {
00660            slot = PK11_ReferenceSlot(token->pk11slot);
00661        } else {
00662            PORT_SetError(SEC_ERROR_NO_TOKEN);
00663            slot = NULL;
00664        }
00665        *delimit = ':';
00666     } else {
00667        slot = PK11_GetInternalKeySlot();
00668        token = PK11Slot_GetNSSToken(slot);
00669     }
00670     if (token) {
00671        PRStatus status;
00672        nssList *nameList;
00673        nssCryptokiObject **instances;
00674        nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
00675        rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
00676        if (rv != SECSuccess) {
00677            PK11_FreeSlot(slot);
00678            if (nickCopy) PORT_Free(nickCopy);
00679            return NULL;
00680        }
00681        collection = nssCertificateCollection_Create(defaultTD, NULL);
00682        if (!collection) {
00683            PK11_FreeSlot(slot);
00684            if (nickCopy) PORT_Free(nickCopy);
00685            return NULL;
00686        }
00687        nameList = nssList_Create(NULL, PR_FALSE);
00688        if (!nameList) {
00689            PK11_FreeSlot(slot);
00690            if (nickCopy) PORT_Free(nickCopy);
00691            return NULL;
00692        }
00693        (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
00694                                                          nickname, 
00695                                                          nameList);
00696        transfer_token_certs_to_collection(nameList, token, collection);
00697        instances = nssToken_FindCertificatesByNickname(token,
00698                                                        NULL,
00699                                                        nickname,
00700                                                        tokenOnly,
00701                                                        0,
00702                                                        &status);
00703        nssPKIObjectCollection_AddInstances(collection, instances, 0);
00704        nss_ZFreeIf(instances);
00705 
00706         /* if it wasn't found, repeat the process for email address */
00707         if (nssPKIObjectCollection_Count(collection) == 0 &&
00708             PORT_Strchr(nickname, '@') != NULL) 
00709         {
00710             char* lowercaseName = CERT_FixupEmailAddr(nickname);
00711             if (lowercaseName) {
00712                 (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 
00713                                                                       lowercaseName, 
00714                                                                       nameList);
00715                 transfer_token_certs_to_collection(nameList, token, collection);
00716                 instances = nssToken_FindCertificatesByEmail(token,
00717                                                              NULL,
00718                                                              lowercaseName,
00719                                                              tokenOnly,
00720                                                              0,
00721                                                              &status);
00722                 nssPKIObjectCollection_AddInstances(collection, instances, 0);
00723                 nss_ZFreeIf(instances);
00724                 PORT_Free(lowercaseName);
00725             }
00726         }
00727 
00728         nssList_Destroy(nameList);
00729        foundCerts = nssPKIObjectCollection_GetCertificates(collection,
00730                                                            NULL, 0, NULL);
00731        nssPKIObjectCollection_Destroy(collection);
00732     }
00733     if (slot) {
00734        PK11_FreeSlot(slot);
00735     }
00736     if (nickCopy) PORT_Free(nickCopy);
00737     if (foundCerts) {
00738        PRTime now = PR_Now();
00739        certList = CERT_NewCertList();
00740        for (i=0, c = *foundCerts; c; c = foundCerts[++i]) {
00741            CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
00742            /* c may be invalid after this, don't reference it */
00743            if (certCert) {
00744                /* CERT_AddCertToListSorted adopts certCert  */
00745               CERT_AddCertToListSorted(certList, certCert,
00746                      CERT_SortCBValidity, &now);
00747            }
00748        }
00749        if (CERT_LIST_HEAD(certList) == NULL) {
00750            CERT_DestroyCertList(certList);
00751            certList = NULL;
00752        }
00753        /* all the certs have been adopted or freed, free the  raw array */
00754        nss_ZFreeIf(foundCerts);
00755     }
00756     return certList;
00757 }
00758 
00759 /*
00760  * extract a key ID for a certificate...
00761  * NOTE: We call this function from PKCS11.c If we ever use
00762  * pkcs11 to extract the public key (we currently do not), this will break.
00763  */
00764 SECItem *
00765 PK11_GetPubIndexKeyID(CERTCertificate *cert) {
00766     SECKEYPublicKey *pubk;
00767     SECItem *newItem = NULL;
00768 
00769     pubk = CERT_ExtractPublicKey(cert);
00770     if (pubk == NULL) return NULL;
00771 
00772     switch (pubk->keyType) {
00773     case rsaKey:
00774        newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
00775        break;
00776     case dsaKey:
00777         newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
00778        break;
00779     case dhKey:
00780         newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
00781        break;
00782     case ecKey:
00783         newItem = SECITEM_DupItem(&pubk->u.ec.publicValue);
00784        break;
00785     case fortezzaKey:
00786     default:
00787        newItem = NULL; /* Fortezza Fix later... */
00788     }
00789     SECKEY_DestroyPublicKey(pubk);
00790     /* make hash of it */
00791     return newItem;
00792 }
00793 
00794 /*
00795  * generate a CKA_ID from a certificate.
00796  */
00797 SECItem *
00798 pk11_mkcertKeyID(CERTCertificate *cert) {
00799     SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ;
00800     SECItem *certCKA_ID;
00801 
00802     if (pubKeyData == NULL) return NULL;
00803     
00804     certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
00805     SECITEM_FreeItem(pubKeyData,PR_TRUE);
00806     return certCKA_ID;
00807 }
00808 
00809 /*
00810  * Write the cert into the token.
00811  */
00812 SECStatus
00813 PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, 
00814               CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) 
00815 {
00816     PRStatus status;
00817     NSSCertificate *c;
00818     nssCryptokiObject *keyobj, *certobj;
00819     NSSToken *token = PK11Slot_GetNSSToken(slot);
00820     SECItem *keyID = pk11_mkcertKeyID(cert);
00821     char *emailAddr = NULL;
00822     nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
00823     nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
00824 
00825     if (keyID == NULL) {
00826        goto loser;
00827     }
00828 
00829     if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) {
00830        emailAddr = cert->emailAddr;
00831     }
00832 
00833     /* need to get the cert as a stan cert */
00834     if (cert->nssCertificate) {
00835        c = cert->nssCertificate;
00836     } else {
00837        c = STAN_GetNSSCertificate(cert);
00838     }
00839 
00840     if (c->object.cryptoContext) {
00841        /* Delete the temp instance */
00842        NSSCryptoContext *cc = c->object.cryptoContext;
00843        nssCertificateStore_Lock(cc->certStore, &lockTrace);
00844        nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
00845        nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace);
00846         nssCertificateStore_Check(&lockTrace, &unlockTrace);
00847        c->object.cryptoContext = NULL;
00848        cert->istemp = PR_FALSE;
00849        cert->isperm = PR_TRUE;
00850     }
00851 
00852     /* set the id for the cert */
00853     nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
00854     if (!c->id.data) {
00855        goto loser;
00856     }
00857 
00858     if (key != CK_INVALID_HANDLE) {
00859        /* create an object for the key, ... */
00860        keyobj = nss_ZNEW(NULL, nssCryptokiObject);
00861        if (!keyobj) {
00862            goto loser;
00863        }
00864        keyobj->token = nssToken_AddRef(token);
00865        keyobj->handle = key;
00866        keyobj->isTokenObject = PR_TRUE;
00867 
00868        /* ... in order to set matching attributes for the key */
00869        status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname, 
00870                                                      &c->id, &c->subject);
00871        nssCryptokiObject_Destroy(keyobj);
00872        if (status != PR_SUCCESS) {
00873            goto loser;
00874        }
00875     }
00876 
00877     /* do the token import */
00878     certobj = nssToken_ImportCertificate(token, NULL,
00879                                          NSSCertificateType_PKIX,
00880                                          &c->id,
00881                                          nickname,
00882                                          &c->encoding,
00883                                          &c->issuer,
00884                                          &c->subject,
00885                                          &c->serial,
00886                                     emailAddr,
00887                                          PR_TRUE);
00888     if (!certobj) {
00889        if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
00890            PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
00891            SECITEM_FreeItem(keyID,PR_TRUE);
00892            return SECFailure;
00893        }
00894        goto loser;
00895     }
00896     /* add the new instance to the cert, force an update of the
00897      * CERTCertificate, and finish
00898      */
00899     nssPKIObject_AddInstance(&c->object, certobj);
00900     nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
00901     (void)STAN_ForceCERTCertificateUpdate(c);
00902     SECITEM_FreeItem(keyID,PR_TRUE);
00903     return SECSuccess;
00904 loser:
00905     SECITEM_FreeItem(keyID,PR_TRUE);
00906     PORT_SetError(SEC_ERROR_ADDING_CERT);
00907     return SECFailure;
00908 }
00909 
00910 SECStatus
00911 PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
00912               CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) {
00913     CERTCertificate *cert;
00914     SECStatus rv;
00915 
00916     cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
00917                                    derCert, NULL, PR_FALSE, PR_TRUE);
00918     if (cert == NULL) return SECFailure;
00919 
00920     rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust);
00921     CERT_DestroyCertificate (cert);
00922     return rv;
00923 }
00924 
00925 /*
00926  * get a certificate handle, look at the cached handle first..
00927  */
00928 CK_OBJECT_HANDLE
00929 pk11_getcerthandle(PK11SlotInfo *slot, CERTCertificate *cert, 
00930                                    CK_ATTRIBUTE *theTemplate,int tsize)
00931 {
00932     CK_OBJECT_HANDLE certh;
00933 
00934     if (cert->slot == slot) {
00935        certh = cert->pkcs11ID;
00936        if ((certh == CK_INVALID_HANDLE) ||
00937                      (cert->series != slot->series)) {
00938             certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
00939             cert->pkcs11ID = certh;
00940             cert->series = slot->series;
00941        }
00942     } else {
00943        certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
00944     }
00945     return certh;
00946 }
00947 
00948 /*
00949  * return the private key From a given Cert
00950  */
00951 SECKEYPrivateKey *
00952 PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
00953                                                          void *wincx) {
00954     int err;
00955     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
00956     CK_ATTRIBUTE theTemplate[] = {
00957        { CKA_VALUE, NULL, 0 },
00958        { CKA_CLASS, NULL, 0 }
00959     };
00960     /* if you change the array, change the variable below as well */
00961     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
00962     CK_OBJECT_HANDLE certh;
00963     CK_OBJECT_HANDLE keyh;
00964     CK_ATTRIBUTE *attrs = theTemplate;
00965     PRBool needLogin;
00966     SECStatus rv;
00967 
00968     PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, 
00969                                           cert->derCert.len); attrs++;
00970     PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
00971 
00972     /*
00973      * issue the find
00974      */
00975     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
00976     if (rv != SECSuccess) {
00977        return NULL;
00978     }
00979 
00980     certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
00981     if (certh == CK_INVALID_HANDLE) {
00982        return NULL;
00983     }
00984     /*
00985      * prevent a login race condition. If slot is logged in between
00986      * our call to pk11_LoginStillRequired and the 
00987      * PK11_MatchItem. The matchItem call will either succeed, or
00988      * we will call it one more time after calling PK11_Authenticate 
00989      * (which is a noop on an authenticated token).
00990      */
00991     needLogin = pk11_LoginStillRequired(slot,wincx);
00992     keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
00993     if ((keyh == CK_INVALID_HANDLE) && needLogin &&
00994                         (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
00995                       SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
00996        /* try it again authenticated */
00997        rv = PK11_Authenticate(slot, PR_TRUE, wincx);
00998        if (rv != SECSuccess) {
00999            return NULL;
01000        }
01001        keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
01002     }
01003     if (keyh == CK_INVALID_HANDLE) { 
01004        return NULL; 
01005     }
01006     return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
01007 } 
01008 
01009 /*
01010  * import a cert for a private key we have already generated. Set the label
01011  * on both to be the nickname. This is for the Key Gen, orphaned key case.
01012  */
01013 PK11SlotInfo *
01014 PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr, 
01015                                                         void *wincx) {
01016     PK11SlotList *list;
01017     PK11SlotListElement *le;
01018     SECItem *keyID;
01019     CK_OBJECT_HANDLE key;
01020     PK11SlotInfo *slot = NULL;
01021     SECStatus rv;
01022     int err;
01023 
01024     keyID = pk11_mkcertKeyID(cert);
01025     /* get them all! */
01026     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
01027     if ((keyID == NULL) || (list == NULL)) {
01028        if (keyID) SECITEM_FreeItem(keyID,PR_TRUE);
01029        if (list) PK11_FreeSlotList(list);
01030        return NULL;
01031     }
01032 
01033     /* Look for the slot that holds the Key */
01034     for (le = list->head ; le; le = le->next) {
01035        /*
01036         * prevent a login race condition. If le->slot is logged in between
01037         * our call to pk11_LoginStillRequired and the 
01038         * pk11_FindPrivateKeyFromCertID, the find will either succeed, or
01039         * we will call it one more time after calling PK11_Authenticate 
01040         * (which is a noop on an authenticated token).
01041         */
01042        PRBool needLogin = pk11_LoginStillRequired(le->slot,wincx);
01043        key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
01044        if ((key == CK_INVALID_HANDLE) && needLogin &&
01045                      (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
01046                       SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
01047            /* authenticate and try again */
01048            rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
01049            if (rv != SECSuccess) continue;
01050            key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
01051        }
01052        if (key != CK_INVALID_HANDLE) {
01053            slot = PK11_ReferenceSlot(le->slot);
01054            if (keyPtr) *keyPtr = key;
01055            break;
01056        }
01057     }
01058 
01059     SECITEM_FreeItem(keyID,PR_TRUE);
01060     PK11_FreeSlotList(list);
01061     return slot;
01062 
01063 }
01064 /*
01065  * import a cert for a private key we have already generated. Set the label
01066  * on both to be the nickname. This is for the Key Gen, orphaned key case.
01067  */
01068 PK11SlotInfo *
01069 PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr, 
01070                                                         void *wincx) {
01071     CERTCertificate *cert;
01072     PK11SlotInfo *slot = NULL;
01073 
01074     /* letting this use go -- the only thing that the cert is used for is
01075      * to get the ID attribute.
01076      */
01077     cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
01078     if (cert == NULL) return NULL;
01079 
01080     slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
01081     CERT_DestroyCertificate (cert);
01082     return slot;
01083 }
01084 
01085 PK11SlotInfo *
01086 PK11_ImportCertForKey(CERTCertificate *cert, char *nickname,void *wincx) {
01087     PK11SlotInfo *slot = NULL;
01088     CK_OBJECT_HANDLE key;
01089 
01090     slot = PK11_KeyForCertExists(cert,&key,wincx);
01091 
01092     if (slot) {
01093        if (PK11_ImportCert(slot,cert,key,nickname,PR_FALSE) != SECSuccess) {
01094            PK11_FreeSlot(slot);
01095            slot = NULL;
01096        }
01097     } else {
01098        PORT_SetError(SEC_ERROR_ADDING_CERT);
01099     }
01100 
01101     return slot;
01102 }
01103 
01104 PK11SlotInfo *
01105 PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,void *wincx) {
01106     CERTCertificate *cert;
01107     PK11SlotInfo *slot = NULL;
01108 
01109     cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
01110                                    derCert, NULL, PR_FALSE, PR_TRUE);
01111     if (cert == NULL) return NULL;
01112 
01113     slot = PK11_ImportCertForKey(cert, nickname, wincx);
01114     CERT_DestroyCertificate (cert);
01115     return slot;
01116 }
01117 
01118 static CK_OBJECT_HANDLE
01119 pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr, 
01120               CK_ATTRIBUTE *searchTemplate, int count, void *wincx) {
01121     PK11SlotList *list;
01122     PK11SlotListElement *le;
01123     CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
01124     PK11SlotInfo *slot = NULL;
01125     SECStatus rv;
01126 
01127     *slotPtr = NULL;
01128 
01129     /* get them all! */
01130     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
01131     if (list == NULL) {
01132        return CK_INVALID_HANDLE;
01133     }
01134 
01135 
01136     /* Look for the slot that holds the Key */
01137     for (le = list->head ; le; le = le->next) {
01138        rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
01139        if (rv != SECSuccess) continue;
01140 
01141        certHandle = pk11_FindObjectByTemplate(le->slot,searchTemplate,count);
01142        if (certHandle != CK_INVALID_HANDLE) {
01143            slot = PK11_ReferenceSlot(le->slot);
01144            break;
01145        }
01146     }
01147 
01148     PK11_FreeSlotList(list);
01149 
01150     if (slot == NULL) {
01151        return CK_INVALID_HANDLE;
01152     }
01153     *slotPtr = slot;
01154     return certHandle;
01155 }
01156 
01157 CERTCertificate *
01158 PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot, 
01159                             CERTIssuerAndSN *issuerSN, void *wincx)
01160 {
01161     CERTCertificate *rvCert = NULL;
01162     NSSCertificate *cert = NULL;
01163     NSSDER issuer, serial;
01164     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
01165     NSSToken *token = slot->nssToken;
01166     nssSession *session;
01167     nssCryptokiObject *instance = NULL;
01168     nssPKIObject *object = NULL;
01169     SECItem *derSerial;
01170     PRStatus status;
01171 
01172     if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
01173         !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 
01174        issuerSN->derIssuer.len    > CERT_MAX_DN_BYTES ||
01175        issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) {
01176        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01177        return NULL;
01178     }
01179 
01180     /* Paranoia */
01181     if (token == NULL) {
01182        PORT_SetError(SEC_ERROR_NO_TOKEN);
01183        return NULL;
01184     }
01185 
01186 
01187     /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
01188      * CERTIssuerAndSN that actually has the encoded value and pass that
01189      * to PKCS#11 (and the crypto context).
01190      */
01191     derSerial = SEC_ASN1EncodeItem(NULL, NULL,
01192                                    &issuerSN->serialNumber,
01193                                    SEC_IntegerTemplate);
01194     if (!derSerial) {
01195        return NULL;
01196     }
01197 
01198     NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
01199     NSSITEM_FROM_SECITEM(&serial, derSerial);
01200 
01201     session = nssToken_GetDefaultSession(token);
01202     if (!session) {
01203        goto loser;
01204     }
01205 
01206     instance = nssToken_FindCertificateByIssuerAndSerialNumber(token,session,
01207               &issuer, &serial, nssTokenSearchType_TokenForced, &status);
01208 
01209     SECITEM_FreeItem(derSerial, PR_TRUE);
01210 
01211     if (!instance) {
01212        goto loser;
01213     }
01214     object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor);
01215     if (!object) {
01216        goto loser;
01217     }
01218     instance = NULL; /* adopted by the previous call */
01219     cert = nssCertificate_Create(object);
01220     if (!cert) {
01221        goto loser;
01222     }
01223     object = NULL; /* adopted by the previous call */
01224     nssTrustDomain_AddCertsToCache(td, &cert,1);
01225     /* on failure, cert is freed below */
01226     rvCert = STAN_GetCERTCertificate(cert);
01227     if (!rvCert) {
01228        goto loser;
01229     }
01230     return rvCert;
01231 
01232 loser:
01233     if (instance) {
01234        nssCryptokiObject_Destroy(instance);
01235     }
01236     if (object) {
01237        nssPKIObject_Destroy(object);
01238     }
01239     if (cert) {
01240        nssCertificate_Destroy(cert);
01241     }
01242     return NULL;
01243 }
01244 
01245 /*
01246  * We're looking for a cert which we have the private key for that's on the
01247  * list of recipients. This searches one slot.
01248  * this is the new version for NSS SMIME code
01249  * this stuff should REALLY be in the SMIME code, but some things in here are not public
01250  * (they should be!)
01251  */
01252 static CERTCertificate *
01253 pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, int *rlIndex, void *pwarg)
01254 {
01255     NSSCMSRecipient *ri = NULL;
01256     int i;
01257 
01258     for (i=0; (ri = recipientlist[i]) != NULL; i++) {
01259        CERTCertificate *cert = NULL;
01260        if (ri->kind == RLSubjKeyID) {
01261            SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
01262            if (derCert) {
01263               cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
01264               SECITEM_FreeItem(derCert, PR_TRUE);
01265            }
01266        } else {
01267            cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN, 
01268                                                pwarg);
01269        }
01270        if (cert) {
01271            /* this isn't our cert */
01272            if ((cert->trust == NULL) ||
01273                      ((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) {
01274                CERT_DestroyCertificate(cert);
01275               continue;
01276            }
01277            ri->slot = PK11_ReferenceSlot(slot);
01278            *rlIndex = i;
01279            return cert;
01280        }
01281     }
01282     *rlIndex = -1;
01283     return NULL;
01284 }
01285 
01286 /*
01287  * This function is the same as above, but it searches all the slots.
01288  * this is the new version for NSS SMIME code
01289  * this stuff should REALLY be in the SMIME code, but some things in here are not public
01290  * (they should be!)
01291  */
01292 static CERTCertificate *
01293 pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
01294 {
01295     PK11SlotList *list;
01296     PK11SlotListElement *le;
01297     CERTCertificate *cert = NULL;
01298     SECStatus rv;
01299 
01300     /* get them all! */
01301     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
01302     if (list == NULL) {
01303        return CK_INVALID_HANDLE;
01304     }
01305 
01306     /* Look for the slot that holds the Key */
01307     for (le = list->head ; le; le = le->next) {
01308        rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
01309        if (rv != SECSuccess) continue;
01310 
01311        cert = pk11_FindCertObjectByRecipientNew(le->slot, 
01312                                    recipientlist, rlIndex, wincx);
01313        if (cert)
01314            break;
01315     }
01316 
01317     PK11_FreeSlotList(list);
01318 
01319     return cert;
01320 }
01321 
01322 /*
01323  * We're looking for a cert which we have the private key for that's on the
01324  * list of recipients. This searches one slot.
01325  */
01326 static CERTCertificate *
01327 pk11_FindCertObjectByRecipient(PK11SlotInfo *slot, 
01328        SEC_PKCS7RecipientInfo **recipientArray,
01329        SEC_PKCS7RecipientInfo **rip, void *pwarg)
01330 {
01331     SEC_PKCS7RecipientInfo *ri = NULL;
01332     int i;
01333 
01334     for (i=0; (ri = recipientArray[i]) != NULL; i++) {
01335        CERTCertificate *cert;
01336 
01337        cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN, 
01338                                                         pwarg);
01339         if (cert) {
01340            /* this isn't our cert */
01341            if ((cert->trust == NULL) ||
01342                      ((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) {
01343                CERT_DestroyCertificate(cert);
01344               continue;
01345            }
01346            *rip = ri;
01347            return cert;
01348        }
01349 
01350     }
01351     *rip = NULL;
01352     return NULL;
01353 }
01354 
01355 /*
01356  * This function is the same as above, but it searches all the slots.
01357  */
01358 static CERTCertificate *
01359 pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr, 
01360        SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip,
01361                                                  void *wincx) {
01362     PK11SlotList *list;
01363     PK11SlotListElement *le;
01364     CERTCertificate * cert = NULL;
01365     PK11SlotInfo *slot = NULL;
01366     SECStatus rv;
01367 
01368     *slotPtr = NULL;
01369 
01370     /* get them all! */
01371     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
01372     if (list == NULL) {
01373        return CK_INVALID_HANDLE;
01374     }
01375 
01376     *rip = NULL;
01377 
01378     /* Look for the slot that holds the Key */
01379     for (le = list->head ; le; le = le->next) {
01380        rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
01381        if (rv != SECSuccess) continue;
01382 
01383        cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray, 
01384                                                  rip, wincx);
01385        if (cert) {
01386            slot = PK11_ReferenceSlot(le->slot);
01387            break;
01388        }
01389     }
01390 
01391     PK11_FreeSlotList(list);
01392 
01393     if (slot == NULL) {
01394        return NULL;
01395     }
01396     *slotPtr = slot;
01397     PORT_Assert(cert != NULL);
01398     return cert;
01399 }
01400 
01401 /*
01402  * We need to invert the search logic for PKCS 7 because if we search for
01403  * each cert on the list over all the slots, we wind up with lots of spurious
01404  * password prompts. This way we get only one password prompt per slot, at
01405  * the max, and most of the time we can find the cert, and only prompt for
01406  * the key...
01407  */
01408 CERTCertificate *
01409 PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr, 
01410        SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip,
01411                             SECKEYPrivateKey**privKey, void *wincx)
01412 {
01413     CERTCertificate *cert = NULL;
01414 
01415     *privKey = NULL;
01416     *slotPtr = NULL;
01417     cert = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx);
01418     if (!cert) {
01419        return NULL;
01420     }
01421 
01422     *privKey = PK11_FindKeyByAnyCert(cert, wincx);
01423     if (*privKey == NULL) {
01424        goto loser;
01425     }
01426 
01427     return cert;
01428 loser:
01429     if (cert) CERT_DestroyCertificate(cert);
01430     if (*slotPtr) PK11_FreeSlot(*slotPtr);
01431     *slotPtr = NULL;
01432     return NULL;
01433 }
01434 
01435 static PRCallOnceType keyIDHashCallOnce;
01436 
01437 static PRStatus PR_CALLBACK
01438 pk11_keyIDHash_populate(void *wincx)
01439 {
01440     CERTCertList     *certList;
01441     CERTCertListNode *node = NULL;
01442     SECItem           subjKeyID = {siBuffer, NULL, 0};
01443 
01444     certList = PK11_ListCerts(PK11CertListUser, wincx);
01445     if (!certList) {
01446        return PR_FAILURE;
01447     }
01448 
01449     for (node = CERT_LIST_HEAD(certList);
01450          !CERT_LIST_END(node, certList);
01451          node = CERT_LIST_NEXT(node)) {
01452        if (CERT_FindSubjectKeyIDExtension(node->cert, 
01453                                           &subjKeyID) == SECSuccess && 
01454            subjKeyID.data != NULL) {
01455            cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert);
01456            SECITEM_FreeItem(&subjKeyID, PR_FALSE);
01457        }
01458     }
01459     CERT_DestroyCertList(certList);
01460     return PR_SUCCESS;
01461 }
01462 
01463 /*
01464  * This is the new version of the above function for NSS SMIME code
01465  * this stuff should REALLY be in the SMIME code, but some things in here are not public
01466  * (they should be!)
01467  */
01468 int
01469 PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
01470 {
01471     CERTCertificate *cert;
01472     NSSCMSRecipient *rl;
01473     PRStatus rv;
01474     int rlIndex;
01475 
01476     rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
01477     if (rv != PR_SUCCESS)
01478        return -1;
01479 
01480     cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
01481     if (!cert) {
01482        return -1;
01483     }
01484 
01485     rl = recipientlist[rlIndex];
01486 
01487     /* at this point, rl->slot is set */
01488 
01489     rl->privkey = PK11_FindKeyByAnyCert(cert, wincx);
01490     if (rl->privkey == NULL) {
01491        goto loser;
01492     }
01493 
01494     /* make a cert from the cert handle */
01495     rl->cert = cert;
01496     return rlIndex;
01497 
01498 loser:
01499     if (cert) CERT_DestroyCertificate(cert);
01500     if (rl->slot) PK11_FreeSlot(rl->slot);
01501     rl->slot = NULL;
01502     return -1;
01503 }
01504 
01505 CERTCertificate *
01506 PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
01507                                                   void *wincx)
01508 {
01509     CERTCertificate *rvCert = NULL;
01510     NSSCertificate *cert;
01511     NSSDER issuer, serial;
01512     NSSCryptoContext *cc;
01513     SECItem *derSerial;
01514 
01515     if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
01516         !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 
01517        issuerSN->derIssuer.len    > CERT_MAX_DN_BYTES ||
01518        issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) {
01519        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01520        return NULL;
01521     }
01522 
01523     if (slotPtr) *slotPtr = NULL;
01524 
01525     /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
01526      * CERTIssuerAndSN that actually has the encoded value and pass that
01527      * to PKCS#11 (and the crypto context).
01528      */
01529     derSerial = SEC_ASN1EncodeItem(NULL, NULL,
01530                                    &issuerSN->serialNumber,
01531                                    SEC_IntegerTemplate);
01532     if (!derSerial) {
01533        return NULL;
01534     }
01535 
01536     NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
01537     NSSITEM_FROM_SECITEM(&serial, derSerial);
01538 
01539     cc = STAN_GetDefaultCryptoContext();
01540     cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc, 
01541                                                                 &issuer, 
01542                                                                 &serial);
01543     if (cert) {
01544        SECITEM_FreeItem(derSerial, PR_TRUE);
01545        return STAN_GetCERTCertificateOrRelease(cert);
01546     }
01547 
01548     do {
01549        /* free the old cert on retry. Associated slot was not present */
01550        if (rvCert) {
01551            CERT_DestroyCertificate(rvCert);
01552            rvCert = NULL;
01553        }
01554 
01555        cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
01556                                                   STAN_GetDefaultTrustDomain(),
01557                                                   &issuer,
01558                                                   &serial);
01559        if (!cert) {
01560            break;
01561        }
01562 
01563        rvCert = STAN_GetCERTCertificateOrRelease(cert);
01564        if (rvCert == NULL) {
01565           break;
01566        }
01567 
01568        /* Check to see if the cert's token is still there */
01569     } while (!PK11_IsPresent(rvCert->slot));
01570 
01571     if (rvCert && slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot);
01572 
01573     SECITEM_FreeItem(derSerial, PR_TRUE);
01574     return rvCert;
01575 }
01576 
01577 CK_OBJECT_HANDLE
01578 PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
01579 {
01580     CK_OBJECT_HANDLE certHandle;
01581     CK_ATTRIBUTE searchTemplate    = { CKA_VALUE, NULL, 0 };
01582     
01583     PK11_SETATTRS(&searchTemplate, CKA_VALUE, cert->derCert.data,
01584                 cert->derCert.len);
01585 
01586     if (cert->slot) {
01587        certHandle = pk11_getcerthandle(cert->slot,cert,&searchTemplate,1);
01588        if (certHandle != CK_INVALID_HANDLE) {
01589            *pSlot = PK11_ReferenceSlot(cert->slot);
01590            return certHandle;
01591        }
01592     }
01593 
01594     certHandle = pk11_FindCertObjectByTemplate(pSlot,&searchTemplate,1,wincx);
01595     if (certHandle != CK_INVALID_HANDLE) {
01596        if (cert->slot == NULL) {
01597            cert->slot = PK11_ReferenceSlot(*pSlot);
01598            cert->pkcs11ID = certHandle;
01599            cert->ownSlot = PR_TRUE;
01600            cert->series = cert->slot->series;
01601        }
01602     }
01603 
01604     return(certHandle);
01605 }
01606 
01607 SECKEYPrivateKey *
01608 PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
01609 {
01610     CK_OBJECT_HANDLE certHandle;
01611     CK_OBJECT_HANDLE keyHandle;
01612     PK11SlotInfo *slot = NULL;
01613     SECKEYPrivateKey *privKey = NULL;
01614     PRBool needLogin;
01615     SECStatus rv;
01616     int err;
01617 
01618     certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
01619     if (certHandle == CK_INVALID_HANDLE) {
01620         return NULL;
01621     }
01622     /*
01623      * prevent a login race condition. If slot is logged in between
01624      * our call to pk11_LoginStillRequired and the 
01625      * PK11_MatchItem. The matchItem call will either succeed, or
01626      * we will call it one more time after calling PK11_Authenticate 
01627      * (which is a noop on an authenticated token).
01628      */
01629     needLogin = pk11_LoginStillRequired(slot,wincx);
01630     keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
01631     if ((keyHandle == CK_INVALID_HANDLE) &&  needLogin &&
01632                      (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
01633                       SEC_ERROR_TOKEN_NOT_LOGGED_IN == err ) ) {
01634        /* authenticate and try again */
01635        rv = PK11_Authenticate(slot, PR_TRUE, wincx);
01636        if (rv == SECSuccess) {
01637             keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
01638        }
01639     }
01640     if (keyHandle != CK_INVALID_HANDLE) { 
01641         privKey =  PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
01642     }
01643     if (slot) {
01644        PK11_FreeSlot(slot);
01645     }
01646     return privKey;
01647 }
01648 
01649 CK_OBJECT_HANDLE
01650 pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
01651 {
01652     CK_OBJECT_HANDLE certHandle;
01653     CK_OBJECT_HANDLE keyHandle;
01654 
01655     certHandle = PK11_FindObjectForCert(cert, wincx, slot);
01656     if (certHandle == CK_INVALID_HANDLE) {
01657         return CK_INVALID_HANDLE;
01658     }
01659     keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY);
01660     if (keyHandle == CK_INVALID_HANDLE) { 
01661        PK11_FreeSlot(*slot);
01662        return CK_INVALID_HANDLE;
01663     }
01664     return keyHandle;
01665 }
01666 
01667 /*
01668  * find the number of certs in the slot with the same subject name
01669  */
01670 int
01671 PK11_NumberCertsForCertSubject(CERTCertificate *cert)
01672 {
01673     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
01674     CK_ATTRIBUTE theTemplate[] = {
01675        { CKA_CLASS, NULL, 0 },
01676        { CKA_SUBJECT, NULL, 0 },
01677     };
01678     CK_ATTRIBUTE *attr = theTemplate;
01679    int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
01680 
01681     PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
01682     PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len);
01683 
01684     if (cert->slot == NULL) {
01685        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
01686                                                  PR_FALSE,PR_TRUE,NULL);
01687        PK11SlotListElement *le;
01688        int count = 0;
01689 
01690        /* loop through all the fortezza tokens */
01691        for (le = list->head; le; le = le->next) {
01692            count += PK11_NumberObjectsFor(le->slot,theTemplate,templateSize);
01693        }
01694        PK11_FreeSlotList(list);
01695        return count;
01696     }
01697 
01698     return PK11_NumberObjectsFor(cert->slot,theTemplate,templateSize);
01699 }
01700 
01701 /*
01702  *  Walk all the certs with the same subject
01703  */
01704 SECStatus
01705 PK11_TraverseCertsForSubject(CERTCertificate *cert,
01706         SECStatus(* callback)(CERTCertificate*, void *), void *arg)
01707 {
01708     if(!cert) {
01709        return SECFailure;
01710     }
01711     if (cert->slot == NULL) {
01712        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
01713                                                  PR_FALSE,PR_TRUE,NULL);
01714        PK11SlotListElement *le;
01715 
01716        /* loop through all the tokens */
01717        for (le = list->head; le; le = le->next) {
01718            PK11_TraverseCertsForSubjectInSlot(cert,le->slot,callback,arg);
01719        }
01720        PK11_FreeSlotList(list);
01721        return SECSuccess;
01722 
01723     }
01724 
01725     return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
01726 }
01727 
01728 SECStatus
01729 PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
01730        SECStatus(* callback)(CERTCertificate*, void *), void *arg)
01731 {
01732     PRStatus nssrv = PR_SUCCESS;
01733     NSSToken *token;
01734     NSSDER subject;
01735     NSSTrustDomain *td;
01736     nssList *subjectList;
01737     nssPKIObjectCollection *collection;
01738     nssCryptokiObject **instances;
01739     NSSCertificate **certs;
01740     nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
01741     td = STAN_GetDefaultTrustDomain();
01742     NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
01743     token = PK11Slot_GetNSSToken(slot);
01744     if (!nssToken_IsPresent(token)) {
01745        return SECSuccess;
01746     }
01747     collection = nssCertificateCollection_Create(td, NULL);
01748     if (!collection) {
01749        return SECFailure;
01750     }
01751     subjectList = nssList_Create(NULL, PR_FALSE);
01752     if (!subjectList) {
01753        nssPKIObjectCollection_Destroy(collection);
01754        return SECFailure;
01755     }
01756     (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject, 
01757                                                      subjectList);
01758     transfer_token_certs_to_collection(subjectList, token, collection);
01759     instances = nssToken_FindCertificatesBySubject(token, NULL,
01760                                                   &subject, 
01761                                                   tokenOnly, 0, &nssrv);
01762     nssPKIObjectCollection_AddInstances(collection, instances, 0);
01763     nss_ZFreeIf(instances);
01764     nssList_Destroy(subjectList);
01765     certs = nssPKIObjectCollection_GetCertificates(collection,
01766                                                    NULL, 0, NULL);
01767     nssPKIObjectCollection_Destroy(collection);
01768     if (certs) {
01769        CERTCertificate *oldie;
01770        NSSCertificate **cp;
01771        for (cp = certs; *cp; cp++) {
01772            oldie = STAN_GetCERTCertificate(*cp);
01773            if (!oldie) {
01774               continue;
01775            }
01776            if ((*callback)(oldie, arg) != SECSuccess) {
01777               nssrv = PR_FAILURE;
01778               break;
01779            }
01780        }
01781        nssCertificateArray_Destroy(certs);
01782     }
01783     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
01784 }
01785 
01786 SECStatus
01787 PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
01788        SECStatus(* callback)(CERTCertificate*, void *), void *arg)
01789 {
01790     struct nss3_cert_cbstr pk11cb;
01791     PRStatus nssrv = PR_SUCCESS;
01792     NSSToken *token;
01793     NSSTrustDomain *td;
01794     NSSUTF8 *nick;
01795     PRBool created = PR_FALSE;
01796     nssCryptokiObject **instances;
01797     nssPKIObjectCollection *collection = NULL;
01798     NSSCertificate **certs;
01799     nssList *nameList = NULL;
01800     nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
01801     pk11cb.callback = callback;
01802     pk11cb.arg = arg;
01803     token = PK11Slot_GetNSSToken(slot);
01804     if (!nssToken_IsPresent(token)) {
01805        return SECSuccess;
01806     }
01807     if (nickname->data[nickname->len-1] != '\0') {
01808        nick = nssUTF8_Create(NULL, nssStringType_UTF8String, 
01809                              nickname->data, nickname->len);
01810        created = PR_TRUE;
01811     } else {
01812        nick = (NSSUTF8 *)nickname->data;
01813     }
01814     td = STAN_GetDefaultTrustDomain();
01815     collection = nssCertificateCollection_Create(td, NULL);
01816     if (!collection) {
01817        goto loser;
01818     }
01819     nameList = nssList_Create(NULL, PR_FALSE);
01820     if (!nameList) {
01821        goto loser;
01822     }
01823     (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
01824     transfer_token_certs_to_collection(nameList, token, collection);
01825     instances = nssToken_FindCertificatesByNickname(token, NULL,
01826                                                    nick,
01827                                                    tokenOnly, 0, &nssrv);
01828     nssPKIObjectCollection_AddInstances(collection, instances, 0);
01829     nss_ZFreeIf(instances);
01830     nssList_Destroy(nameList);
01831     certs = nssPKIObjectCollection_GetCertificates(collection,
01832                                                    NULL, 0, NULL);
01833     nssPKIObjectCollection_Destroy(collection);
01834     if (certs) {
01835        CERTCertificate *oldie;
01836        NSSCertificate **cp;
01837        for (cp = certs; *cp; cp++) {
01838            oldie = STAN_GetCERTCertificate(*cp);
01839            if (!oldie) {
01840               continue;
01841            }
01842            if ((*callback)(oldie, arg) != SECSuccess) {
01843               nssrv = PR_FAILURE;
01844               break;
01845            }
01846        }
01847        nssCertificateArray_Destroy(certs);
01848     }
01849     if (created) nss_ZFreeIf(nick);
01850     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
01851 loser:
01852     if (created) {
01853        nss_ZFreeIf(nick);
01854     }
01855     if (collection) {
01856        nssPKIObjectCollection_Destroy(collection);
01857     }
01858     if (nameList) {
01859        nssList_Destroy(nameList);
01860     }
01861     return SECFailure;
01862 }
01863 
01864 SECStatus
01865 PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
01866        SECStatus(* callback)(CERTCertificate*, void *), void *arg)
01867 {
01868     PRStatus nssrv;
01869     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
01870     NSSToken *tok;
01871     nssList *certList = NULL;
01872     nssCryptokiObject **instances;
01873     nssPKIObjectCollection *collection;
01874     NSSCertificate **certs;
01875     nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
01876     tok = PK11Slot_GetNSSToken(slot);
01877     if (!nssToken_IsPresent(tok)) {
01878        return SECSuccess;
01879     }
01880     collection = nssCertificateCollection_Create(td, NULL);
01881     if (!collection) {
01882        return SECFailure;
01883     }
01884     certList = nssList_Create(NULL, PR_FALSE);
01885     if (!certList) {
01886        nssPKIObjectCollection_Destroy(collection);
01887        return SECFailure;
01888     }
01889     (void *)nssTrustDomain_GetCertsFromCache(td, certList);
01890     transfer_token_certs_to_collection(certList, tok, collection);
01891     instances = nssToken_FindCertificates(tok, NULL,
01892                                           tokenOnly, 0, &nssrv);
01893     nssPKIObjectCollection_AddInstances(collection, instances, 0);
01894     nss_ZFreeIf(instances);
01895     nssList_Destroy(certList);
01896     certs = nssPKIObjectCollection_GetCertificates(collection,
01897                                                    NULL, 0, NULL);
01898     nssPKIObjectCollection_Destroy(collection);
01899     if (certs) {
01900        CERTCertificate *oldie;
01901        NSSCertificate **cp;
01902        for (cp = certs; *cp; cp++) {
01903            oldie = STAN_GetCERTCertificate(*cp);
01904            if (!oldie) {
01905               continue;
01906            }
01907            if ((*callback)(oldie, arg) != SECSuccess) {
01908               nssrv = PR_FAILURE;
01909               break;
01910            }
01911        }
01912        nssCertificateArray_Destroy(certs);
01913     }
01914     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
01915 }
01916 
01917 /*
01918  * return the certificate associated with a derCert 
01919  */
01920 CERTCertificate *
01921 PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
01922                                                          void *wincx)
01923 {
01924     return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
01925 }
01926 
01927 CERTCertificate *
01928 PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert,
01929                                                          void *wincx)
01930 
01931 {
01932     NSSCertificate *c;
01933     NSSDER derCert;
01934     NSSToken *tok;
01935     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
01936     SECStatus rv;
01937 
01938     tok = PK11Slot_GetNSSToken(slot);
01939     NSSITEM_FROM_SECITEM(&derCert, inDerCert);
01940     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
01941     if (rv != SECSuccess) {
01942        PK11_FreeSlot(slot);
01943        return NULL;
01944     }
01945     c = NSSTrustDomain_FindCertificateByEncodedCertificate(td, &derCert);
01946     if (c) {
01947        PRBool isToken = PR_FALSE;
01948        NSSToken **tp;
01949        NSSToken **tokens = nssPKIObject_GetTokens(&c->object, NULL);
01950        if (tokens) {
01951            for (tp = tokens; *tp; tp++) {
01952               if (*tp == tok) {
01953                   isToken = PR_TRUE;
01954                   break;
01955               }
01956            }
01957            if (!isToken) {
01958               NSSCertificate_Destroy(c);
01959               c = NULL;
01960            }
01961            nssTokenArray_Destroy(tokens);
01962        }
01963     }
01964     return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
01965 } 
01966 
01967 /* mcgreer 3.4 -- nobody uses this, ignoring */
01968 /*
01969  * return the certificate associated with a derCert 
01970  */
01971 CERTCertificate *
01972 PK11_FindCertFromDERSubjectAndNickname(PK11SlotInfo *slot, 
01973                                    CERTCertificate *cert, 
01974                                    char *nickname, void *wincx)
01975 {
01976     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
01977     CK_ATTRIBUTE theTemplate[] = {
01978        { CKA_SUBJECT, NULL, 0 },
01979        { CKA_LABEL, NULL, 0 },
01980        { CKA_CLASS, NULL, 0 }
01981     };
01982     /* if you change the array, change the variable below as well */
01983     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
01984     CK_OBJECT_HANDLE certh;
01985     CK_ATTRIBUTE *attrs = theTemplate;
01986     SECStatus rv;
01987 
01988     PK11_SETATTRS(attrs, CKA_SUBJECT, cert->derSubject.data, 
01989                                           cert->derSubject.len); attrs++;
01990     PK11_SETATTRS(attrs, CKA_LABEL, nickname, PORT_Strlen(nickname));
01991     PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
01992 
01993     /*
01994      * issue the find
01995      */
01996     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
01997     if (rv != SECSuccess) return NULL;
01998 
01999     certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
02000     if (certh == CK_INVALID_HANDLE) {
02001        return NULL;
02002     }
02003 
02004     return PK11_MakeCertFromHandle(slot, certh, NULL);
02005 }
02006 
02007 /*
02008  * import a cert for a private key we have already generated. Set the label
02009  * on both to be the nickname.
02010  */
02011 static CK_OBJECT_HANDLE 
02012 pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
02013                                                         void *wincx)
02014 {
02015     SECItem *keyID;
02016     CK_OBJECT_HANDLE key;
02017     SECStatus rv;
02018     PRBool needLogin;
02019     int err;
02020 
02021     if((slot == NULL) || (cert == NULL)) {
02022        return CK_INVALID_HANDLE;
02023     }
02024 
02025     keyID = pk11_mkcertKeyID(cert);
02026     if(keyID == NULL) {
02027        return CK_INVALID_HANDLE;
02028     }
02029 
02030     /*
02031      * prevent a login race condition. If slot is logged in between
02032      * our call to pk11_LoginStillRequired and the 
02033      * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or
02034      * we will call it one more time after calling PK11_Authenticate 
02035      * (which is a noop on an authenticated token).
02036      */
02037     needLogin = pk11_LoginStillRequired(slot,wincx);
02038     key = pk11_FindPrivateKeyFromCertID(slot, keyID);
02039     if ((key == CK_INVALID_HANDLE) && needLogin &&
02040                      (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
02041                       SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
02042        /* authenticate and try again */
02043        rv = PK11_Authenticate(slot, PR_TRUE, wincx);
02044        if (rv != SECSuccess) goto loser;
02045        key = pk11_FindPrivateKeyFromCertID(slot, keyID);
02046    }
02047 
02048 loser:
02049     SECITEM_ZfreeItem(keyID, PR_TRUE);
02050     return key;
02051 }
02052 
02053 SECKEYPrivateKey *
02054 PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
02055                                                         void *wincx)
02056 {
02057     CK_OBJECT_HANDLE keyHandle;
02058 
02059     if((slot == NULL) || (cert == NULL)) {
02060        return NULL;
02061     }
02062 
02063     keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
02064     if (keyHandle == CK_INVALID_HANDLE) {
02065        return NULL;
02066     }
02067 
02068     return PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,wincx);
02069 }
02070 
02071 SECStatus
02072 PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, 
02073                                           char *nickname, 
02074                                           PRBool addCertUsage,void *wincx)
02075 {
02076     CK_OBJECT_HANDLE keyHandle;
02077 
02078     if((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
02079        return SECFailure;
02080     }
02081 
02082     keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
02083     if (keyHandle == CK_INVALID_HANDLE) {
02084        return SECFailure;
02085     }
02086 
02087     return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
02088 }   
02089 
02090 
02091 /* remove when the real version comes out */
02092 #define SEC_OID_MISSI_KEA 300  /* until we have v3 stuff merged */
02093 PRBool
02094 KEAPQGCompare(CERTCertificate *server,CERTCertificate *cert) {
02095 
02096     if ( SECKEY_KEAParamCompare(server,cert) == SECEqual ) {
02097         return PR_TRUE;
02098     } else {
02099        return PR_FALSE;
02100     }
02101 }
02102 
02103 PRBool
02104 PK11_FortezzaHasKEA(CERTCertificate *cert) {
02105    /* look at the subject and see if it is a KEA for MISSI key */
02106    SECOidData *oid;
02107 
02108    if ((cert->trust == NULL) ||
02109        ((cert->trust->sslFlags & CERTDB_USER) != CERTDB_USER)) {
02110        return PR_FALSE;
02111    }
02112 
02113    oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
02114 
02115 
02116    return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) || 
02117               (oid->offset == SEC_OID_MISSI_KEA_DSS) ||
02118                             (oid->offset == SEC_OID_MISSI_KEA)) ;
02119 }
02120 
02121 /*
02122  * Find a kea cert on this slot that matches the domain of it's peer
02123  */
02124 static CERTCertificate
02125 *pk11_GetKEAMate(PK11SlotInfo *slot,CERTCertificate *peer)
02126 {
02127     int i;
02128     CERTCertificate *returnedCert = NULL;
02129 
02130     for (i=0; i < slot->cert_count; i++) {
02131        CERTCertificate *cert = slot->cert_array[i];
02132 
02133        if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer,cert)) {
02134               returnedCert = CERT_DupCertificate(cert);
02135               break;
02136        }
02137     }
02138     return returnedCert;
02139 }
02140 
02141 /*
02142  * The following is a FORTEZZA only Certificate request. We call this when we
02143  * are doing a non-client auth SSL connection. We are only interested in the
02144  * fortezza slots, and we are only interested in certs that share the same root
02145  * key as the server.
02146  */
02147 CERTCertificate *
02148 PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
02149 {
02150     PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
02151                                                  PR_FALSE,PR_TRUE,wincx);
02152     PK11SlotListElement *le;
02153     CERTCertificate *returnedCert = NULL;
02154     SECStatus rv;
02155 
02156     /* loop through all the fortezza tokens */
02157     for (le = keaList->head; le; le = le->next) {
02158         rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
02159         if (rv != SECSuccess) continue;
02160        if (le->slot->session == CK_INVALID_SESSION) {
02161            continue;
02162        }
02163        returnedCert = pk11_GetKEAMate(le->slot,server);
02164        if (returnedCert) break;
02165     }
02166     PK11_FreeSlotList(keaList);
02167 
02168     return returnedCert;
02169 }
02170 
02171 /*
02172  * find a matched pair of kea certs to key exchange parameters from one 
02173  * fortezza card to another as necessary.
02174  */
02175 SECStatus
02176 PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
02177        CERTCertificate **cert1, CERTCertificate **cert2)
02178 {
02179     CERTCertificate *returnedCert = NULL;
02180     int i;
02181 
02182     for (i=0; i < slot1->cert_count; i++) {
02183        CERTCertificate *cert = slot1->cert_array[i];
02184 
02185        if (PK11_FortezzaHasKEA(cert)) {
02186            returnedCert = pk11_GetKEAMate(slot2,cert);
02187            if (returnedCert != NULL) {
02188               *cert2 = returnedCert;
02189               *cert1 = CERT_DupCertificate(cert);
02190               return SECSuccess;
02191            }
02192        }
02193     }
02194     return SECFailure;
02195 }
02196 
02197 /*
02198  * return the private key From a given Cert
02199  */
02200 CK_OBJECT_HANDLE
02201 PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
02202 {
02203     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
02204     CK_ATTRIBUTE theTemplate[] = {
02205        { CKA_VALUE, NULL, 0 },
02206        { CKA_CLASS, NULL, 0 }
02207     };
02208     /* if you change the array, change the variable below as well */
02209     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
02210     CK_ATTRIBUTE *attrs = theTemplate;
02211     SECStatus rv;
02212 
02213     PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
02214                                           cert->derCert.len); attrs++;
02215     PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
02216 
02217     /*
02218      * issue the find
02219      */
02220     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
02221     if (rv != SECSuccess) {
02222        return CK_INVALID_HANDLE;
02223     }
02224 
02225     return pk11_getcerthandle(slot,cert,theTemplate,tsize);
02226 }
02227 
02228 SECItem *
02229 PK11_GetKeyIDFromCert(CERTCertificate *cert, void *wincx)
02230 {
02231     CK_OBJECT_HANDLE handle;
02232     PK11SlotInfo *slot = NULL;
02233     CK_ATTRIBUTE theTemplate[] = {
02234        { CKA_ID, NULL, 0 },
02235     };
02236     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
02237     SECItem *item = NULL;
02238     CK_RV crv;
02239 
02240     handle = PK11_FindObjectForCert(cert,wincx,&slot);
02241     if (handle == CK_INVALID_HANDLE) {
02242        goto loser;
02243     }
02244 
02245     crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize);
02246     if (crv != CKR_OK) {
02247        PORT_SetError( PK11_MapError(crv) );
02248        goto loser;
02249     }
02250 
02251     item = PORT_ZNew(SECItem);
02252     if (item) {
02253         item->data = (unsigned char*) theTemplate[0].pValue;
02254         item->len = theTemplate[0].ulValueLen;
02255     }
02256 
02257 loser:
02258     PK11_FreeSlot(slot);
02259     return item;
02260 }
02261 
02262 struct listCertsStr {
02263     PK11CertListType type;
02264     CERTCertList *certList;
02265 };
02266 
02267 static PRStatus
02268 pk11ListCertCallback(NSSCertificate *c, void *arg)
02269 {
02270     struct listCertsStr *listCertP = (struct listCertsStr *)arg;
02271     CERTCertificate *newCert = NULL;
02272     PK11CertListType type = listCertP->type;
02273     CERTCertList *certList = listCertP->certList;
02274     PRBool isUnique = PR_FALSE;
02275     PRBool isCA = PR_FALSE;
02276     char *nickname = NULL;
02277     unsigned int certType;
02278 
02279     if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) ||
02280         (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique) ) {
02281         /* only list one instance of each certificate, even if several exist */
02282        isUnique = PR_TRUE;
02283     }
02284     if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) ||
02285         (type == PK11CertListCAUnique)) {
02286        isCA = PR_TRUE;
02287     }
02288 
02289     /* if we want user certs and we don't have one skip this cert */
02290     if ( ( (type == PK11CertListUser) || (type == PK11CertListUserUnique) ) && 
02291               !NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
02292        return PR_SUCCESS;
02293     }
02294 
02295     /* PK11CertListRootUnique means we want CA certs without a private key.
02296      * This is for legacy app support . PK11CertListCAUnique should be used
02297      * instead to get all CA certs, regardless of private key
02298      */
02299     if ((type == PK11CertListRootUnique) && 
02300               NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
02301        return PR_SUCCESS;
02302     }
02303 
02304     /* caller still owns the reference to 'c' */
02305     newCert = STAN_GetCERTCertificate(c);
02306     if (!newCert) {
02307        return PR_SUCCESS;
02308     }
02309     /* if we want CA certs and it ain't one, skip it */
02310     if( isCA  && (!CERT_IsCACert(newCert, &certType)) ) {
02311        return PR_SUCCESS;
02312     }
02313     if (isUnique) {
02314        CERT_DupCertificate(newCert);
02315 
02316        nickname = STAN_GetCERTCertificateName(certList->arena, c);
02317 
02318        /* put slot certs at the end */
02319        if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
02320            CERT_AddCertToListTailWithData(certList,newCert,nickname);
02321        } else {
02322            CERT_AddCertToListHeadWithData(certList,newCert,nickname);
02323        }
02324     } else {
02325        /* add multiple instances to the cert list */
02326        nssCryptokiObject **ip;
02327        nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
02328        if (!instances) {
02329            return PR_SUCCESS;
02330        }
02331        for (ip = instances; *ip; ip++) {
02332            nssCryptokiObject *instance = *ip;
02333            PK11SlotInfo *slot = instance->token->pk11slot;
02334 
02335            /* put the same CERTCertificate in the list for all instances */
02336            CERT_DupCertificate(newCert);
02337 
02338            nickname = STAN_GetCERTCertificateNameForInstance(
02339                      certList->arena, c, instance);
02340 
02341            /* put slot certs at the end */
02342            if (slot && !PK11_IsInternal(slot)) {
02343               CERT_AddCertToListTailWithData(certList,newCert,nickname);
02344            } else {
02345               CERT_AddCertToListHeadWithData(certList,newCert,nickname);
02346            }
02347        }
02348        nssCryptokiObjectArray_Destroy(instances);
02349     }
02350     return PR_SUCCESS;
02351 }
02352 
02353 
02354 CERTCertList *
02355 PK11_ListCerts(PK11CertListType type, void *pwarg)
02356 {
02357     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
02358     CERTCertList *certList = NULL;
02359     struct listCertsStr listCerts;
02360     certList = CERT_NewCertList();
02361     listCerts.type = type;
02362     listCerts.certList = certList;
02363 
02364     /* authenticate to the slots */
02365     (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, pwarg);
02366     NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback,
02367                                                          &listCerts);
02368     return certList;
02369 }
02370     
02371 SECItem *
02372 PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
02373                                    CERTCertificate *cert, void *wincx)
02374 {
02375     CK_ATTRIBUTE theTemplate[] = {
02376        { CKA_VALUE, NULL, 0 },
02377        { CKA_CLASS, NULL, 0 }
02378     };
02379     /* if you change the array, change the variable below as well */
02380     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
02381     CK_OBJECT_HANDLE certHandle;
02382     CK_ATTRIBUTE *attrs = theTemplate;
02383     PK11SlotInfo *slotRef = NULL;
02384     SECItem *item;
02385     SECStatus rv;
02386 
02387     if (slot) {
02388        PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, 
02389                                           cert->derCert.len); attrs++;
02390  
02391        rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
02392        if (rv != SECSuccess) {
02393            return NULL;
02394        }
02395         certHandle = pk11_getcerthandle(slot,cert,theTemplate,tsize);
02396     } else {
02397        certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
02398        if (certHandle == CK_INVALID_HANDLE) {
02399           return pk11_mkcertKeyID(cert);
02400        }
02401        slot = slotRef;
02402     }
02403 
02404     if (certHandle == CK_INVALID_HANDLE) {
02405         return NULL;
02406     }
02407 
02408     item = pk11_GetLowLevelKeyFromHandle(slot,certHandle);
02409     if (slotRef) PK11_FreeSlot(slotRef);
02410     return item;
02411 }
02412 
02413 /* argument type for listCertsCallback */
02414 typedef struct {
02415     CERTCertList *list;
02416     PK11SlotInfo *slot;
02417 } ListCertsArg;
02418 
02419 static SECStatus
02420 listCertsCallback(CERTCertificate* cert, void*arg)
02421 {
02422     ListCertsArg *cdata = (ListCertsArg*)arg;
02423     char *nickname = NULL;
02424     nssCryptokiObject *instance, **ci;
02425     nssCryptokiObject **instances;
02426     NSSCertificate *c = STAN_GetNSSCertificate(cert);
02427 
02428     instances = nssPKIObject_GetInstances(&c->object);
02429     if (!instances) {
02430         return SECFailure;
02431     }
02432     instance = NULL;
02433     for (ci = instances; *ci; ci++) {
02434        if ((*ci)->token->pk11slot == cdata->slot) {
02435            instance = *ci;
02436            break;
02437        }
02438     }
02439     PORT_Assert(instance != NULL);
02440     if (!instance) {
02441        nssCryptokiObjectArray_Destroy(instances);
02442        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02443        return SECFailure;
02444     }
02445     nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena,
02446        c, instance);
02447     nssCryptokiObjectArray_Destroy(instances);
02448 
02449     return CERT_AddCertToListTailWithData(cdata->list, 
02450                             CERT_DupCertificate(cert),nickname);
02451 }
02452 
02453 CERTCertList *
02454 PK11_ListCertsInSlot(PK11SlotInfo *slot)
02455 {
02456     SECStatus status;
02457     CERTCertList *certs;
02458     ListCertsArg cdata;
02459 
02460     certs = CERT_NewCertList();
02461     if(certs == NULL) return NULL;
02462     cdata.list = certs;
02463     cdata.slot = slot;
02464 
02465     status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
02466               &cdata);
02467 
02468     if( status != SECSuccess ) {
02469        CERT_DestroyCertList(certs);
02470        certs = NULL;
02471     }
02472 
02473     return certs;
02474 }
02475