Back to index

lightning-sunbird  0.9+nobinonly
pkibase.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.25.28.1 $ $Date: 2006/08/23 01:36:31 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef DEV_H
00042 #include "dev.h"
00043 #endif /* DEV_H */
00044 
00045 #ifndef PKIM_H
00046 #include "pkim.h"
00047 #endif /* PKIM_H */
00048 
00049 #ifdef NSS_3_4_CODE
00050 #include "pki3hack.h"
00051 #endif
00052 
00053 extern const NSSError NSS_ERROR_NOT_FOUND;
00054 
00055 NSS_IMPLEMENT void
00056 nssPKIObject_Lock(nssPKIObject * object)
00057 {
00058     switch (object->lockType) {
00059     case nssPKIMonitor:
00060         PZ_EnterMonitor(object->sync.mlock);
00061         break;
00062     case nssPKILock:
00063         PZ_Lock(object->sync.lock);
00064         break;
00065     default:
00066         PORT_Assert(0);
00067     }
00068 }
00069 
00070 NSS_IMPLEMENT void
00071 nssPKIObject_Unlock(nssPKIObject * object)
00072 {
00073     switch (object->lockType) {
00074     case nssPKIMonitor:
00075         PZ_ExitMonitor(object->sync.mlock);
00076         break;
00077     case nssPKILock:
00078         PZ_Unlock(object->sync.lock);
00079         break;
00080     default:
00081         PORT_Assert(0);
00082     }
00083 }
00084 
00085 NSS_IMPLEMENT PRStatus
00086 nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType)
00087 {
00088     object->lockType = lockType;
00089     switch (lockType) {
00090     case nssPKIMonitor:
00091         object->sync.mlock = PZ_NewMonitor(nssILockSSL);
00092         return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
00093     case nssPKILock:
00094         object->sync.lock = PZ_NewLock(nssILockSSL);
00095         return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
00096     default:
00097         PORT_Assert(0);
00098         return PR_FAILURE;
00099     }
00100 }
00101 
00102 NSS_IMPLEMENT void
00103 nssPKIObject_DestroyLock(nssPKIObject * object)
00104 {
00105     switch (object->lockType) {
00106     case nssPKIMonitor:
00107         PZ_DestroyMonitor(object->sync.mlock);
00108         object->sync.mlock = NULL;
00109         break;
00110     case nssPKILock:
00111         PZ_DestroyLock(object->sync.lock);
00112         object->sync.lock = NULL;
00113         break;
00114     default:
00115         PORT_Assert(0);
00116     }
00117 }
00118 
00119 
00120 
00121 NSS_IMPLEMENT nssPKIObject *
00122 nssPKIObject_Create (
00123   NSSArena *arenaOpt,
00124   nssCryptokiObject *instanceOpt,
00125   NSSTrustDomain *td,
00126   NSSCryptoContext *cc,
00127   nssPKILockType lockType
00128 )
00129 {
00130     NSSArena *arena;
00131     nssArenaMark *mark = NULL;
00132     nssPKIObject *object;
00133     if (arenaOpt) {
00134        arena = arenaOpt;
00135        mark = nssArena_Mark(arena);
00136     } else {
00137        arena = nssArena_Create();
00138        if (!arena) {
00139            return (nssPKIObject *)NULL;
00140        }
00141     }
00142     object = nss_ZNEW(arena, nssPKIObject);
00143     if (!object) {
00144        goto loser;
00145     }
00146     object->arena = arena;
00147     object->trustDomain = td; /* XXX */
00148     object->cryptoContext = cc;
00149     if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
00150        goto loser;
00151     }
00152     if (instanceOpt) {
00153        if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
00154            goto loser;
00155        }
00156     }
00157     PR_AtomicIncrement(&object->refCount);
00158     if (mark) {
00159        nssArena_Unmark(arena, mark);
00160     }
00161     return object;
00162 loser:
00163     if (mark) {
00164        nssArena_Release(arena, mark);
00165     } else {
00166        nssArena_Destroy(arena);
00167     }
00168     return (nssPKIObject *)NULL;
00169 }
00170 
00171 NSS_IMPLEMENT PRBool
00172 nssPKIObject_Destroy (
00173   nssPKIObject *object
00174 )
00175 {
00176     PRUint32 i;
00177     PR_ASSERT(object->refCount > 0);
00178     if (PR_AtomicDecrement(&object->refCount) == 0) {
00179        for (i=0; i<object->numInstances; i++) {
00180            nssCryptokiObject_Destroy(object->instances[i]);
00181        }
00182        nssPKIObject_DestroyLock(object);
00183        nssArena_Destroy(object->arena);
00184        return PR_TRUE;
00185     }
00186     return PR_FALSE;
00187 }
00188 
00189 NSS_IMPLEMENT nssPKIObject *
00190 nssPKIObject_AddRef (
00191   nssPKIObject *object
00192 )
00193 {
00194     PR_AtomicIncrement(&object->refCount);
00195     return object;
00196 }
00197 
00198 NSS_IMPLEMENT PRStatus
00199 nssPKIObject_AddInstance (
00200   nssPKIObject *object,
00201   nssCryptokiObject *instance
00202 )
00203 {
00204     nssPKIObject_Lock(object);
00205     if (object->numInstances == 0) {
00206        object->instances = nss_ZNEWARRAY(object->arena,
00207                                          nssCryptokiObject *,
00208                                          object->numInstances + 1);
00209     } else {
00210        PRUint32 i;
00211        for (i=0; i<object->numInstances; i++) {
00212            if (nssCryptokiObject_Equal(object->instances[i], instance)) {
00213               nssPKIObject_Unlock(object);
00214               if (instance->label) {
00215                   if (!object->instances[i]->label ||
00216                       !nssUTF8_Equal(instance->label,
00217                                      object->instances[i]->label, NULL))
00218                   {
00219                      /* Either the old instance did not have a label,
00220                       * or the label has changed.
00221                       */
00222                      nss_ZFreeIf(object->instances[i]->label);
00223                      object->instances[i]->label = instance->label;
00224                      instance->label = NULL;
00225                   }
00226               } else if (object->instances[i]->label) {
00227                   /* The old label was removed */
00228                   nss_ZFreeIf(object->instances[i]->label);
00229                   object->instances[i]->label = NULL;
00230               }
00231               nssCryptokiObject_Destroy(instance);
00232               return PR_SUCCESS;
00233            }
00234        }
00235        object->instances = nss_ZREALLOCARRAY(object->instances,
00236                                              nssCryptokiObject *,
00237                                              object->numInstances + 1);
00238     }
00239     if (!object->instances) {
00240        nssPKIObject_Unlock(object);
00241        return PR_FAILURE;
00242     }
00243     object->instances[object->numInstances++] = instance;
00244     nssPKIObject_Unlock(object);
00245     return PR_SUCCESS;
00246 }
00247 
00248 NSS_IMPLEMENT PRBool
00249 nssPKIObject_HasInstance (
00250   nssPKIObject *object,
00251   nssCryptokiObject *instance
00252 )
00253 {
00254     PRUint32 i;
00255     PRBool hasIt = PR_FALSE;;
00256     nssPKIObject_Lock(object);
00257     for (i=0; i<object->numInstances; i++) {
00258        if (nssCryptokiObject_Equal(object->instances[i], instance)) {
00259            hasIt = PR_TRUE;
00260            break;
00261        }
00262     }
00263     nssPKIObject_Unlock(object);
00264     return hasIt;
00265 }
00266 
00267 NSS_IMPLEMENT PRStatus
00268 nssPKIObject_RemoveInstanceForToken (
00269   nssPKIObject *object,
00270   NSSToken *token
00271 )
00272 {
00273     PRUint32 i;
00274     nssCryptokiObject *instanceToRemove = NULL;
00275     nssPKIObject_Lock(object);
00276     if (object->numInstances == 0) {
00277        nssPKIObject_Unlock(object);
00278        return PR_SUCCESS;
00279     }
00280     for (i=0; i<object->numInstances; i++) {
00281        if (object->instances[i]->token == token) {
00282            instanceToRemove = object->instances[i];
00283            object->instances[i] = object->instances[object->numInstances-1];
00284            object->instances[object->numInstances-1] = NULL;
00285            break;
00286        }
00287     }
00288     if (--object->numInstances > 0) {
00289        nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
00290                                              nssCryptokiObject *,
00291                                              object->numInstances);
00292        if (instances) {
00293            object->instances = instances;
00294        }
00295     } else {
00296        nss_ZFreeIf(object->instances);
00297     }
00298     nssCryptokiObject_Destroy(instanceToRemove);
00299     nssPKIObject_Unlock(object);
00300     return PR_SUCCESS;
00301 }
00302 
00303 /* this needs more thought on what will happen when there are multiple
00304  * instances
00305  */
00306 NSS_IMPLEMENT PRStatus
00307 nssPKIObject_DeleteStoredObject (
00308   nssPKIObject *object,
00309   NSSCallback *uhh,
00310   PRBool isFriendly
00311 )
00312 {
00313     PRUint32 i, numNotDestroyed;
00314     PRStatus status = PR_SUCCESS;
00315 #ifndef NSS_3_4_CODE
00316     NSSTrustDomain *td = object->trustDomain;
00317     NSSCallback *pwcb = uhh ?  /* is this optional? */
00318                         uhh : 
00319                         nssTrustDomain_GetDefaultCallback(td, NULL);
00320 #endif
00321     numNotDestroyed = 0;
00322     nssPKIObject_Lock(object);
00323     for (i=0; i<object->numInstances; i++) {
00324        nssCryptokiObject *instance = object->instances[i];
00325 #ifndef NSS_3_4_CODE
00326        NSSSlot *slot = nssToken_GetSlot(instance->token);
00327        /* If both the operation and the slot are friendly, login is
00328         * not required.  If either or both are not friendly, it is
00329         * required.
00330         */
00331        if (!(isFriendly && nssSlot_IsFriendly(slot))) {
00332            status = nssSlot_Login(slot, pwcb);
00333            nssSlot_Destroy(slot);
00334            if (status == PR_SUCCESS) {
00335               /* XXX this should be fixed to understand read-only tokens,
00336                * for now, to handle the builtins, just make the attempt.
00337                */
00338               status = nssToken_DeleteStoredObject(instance);
00339            }
00340        }
00341 #else
00342        status = nssToken_DeleteStoredObject(instance);
00343 #endif
00344        object->instances[i] = NULL;
00345        if (status == PR_SUCCESS) {
00346            nssCryptokiObject_Destroy(instance);
00347        } else {
00348            object->instances[numNotDestroyed++] = instance;
00349        }
00350     }
00351     if (numNotDestroyed == 0) {
00352        nss_ZFreeIf(object->instances);
00353        object->numInstances = 0;
00354     } else {
00355        object->numInstances = numNotDestroyed;
00356     }
00357     nssPKIObject_Unlock(object);
00358     return status;
00359 }
00360 
00361 NSS_IMPLEMENT NSSToken **
00362 nssPKIObject_GetTokens (
00363   nssPKIObject *object,
00364   PRStatus *statusOpt
00365 )
00366 {
00367     NSSToken **tokens = NULL;
00368     nssPKIObject_Lock(object);
00369     if (object->numInstances > 0) {
00370        tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
00371        if (tokens) {
00372            PRUint32 i;
00373            for (i=0; i<object->numInstances; i++) {
00374               tokens[i] = nssToken_AddRef(object->instances[i]->token);
00375            }
00376        }
00377     }
00378     nssPKIObject_Unlock(object);
00379     if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */
00380     return tokens;
00381 }
00382 
00383 NSS_IMPLEMENT NSSUTF8 *
00384 nssPKIObject_GetNicknameForToken (
00385   nssPKIObject *object,
00386   NSSToken *tokenOpt
00387 )
00388 {
00389     PRUint32 i;
00390     NSSUTF8 *nickname = NULL;
00391     nssPKIObject_Lock(object);
00392     for (i=0; i<object->numInstances; i++) {
00393        if ((!tokenOpt && object->instances[i]->label) ||
00394            (object->instances[i]->token == tokenOpt)) 
00395        {
00396             /* XXX should be copy? safe as long as caller has reference */
00397            nickname = object->instances[i]->label; 
00398            break;
00399        }
00400     }
00401     nssPKIObject_Unlock(object);
00402     return nickname;
00403 }
00404 
00405 #ifdef NSS_3_4_CODE
00406 NSS_IMPLEMENT nssCryptokiObject **
00407 nssPKIObject_GetInstances (
00408   nssPKIObject *object
00409 )
00410 {
00411     nssCryptokiObject **instances = NULL;
00412     PRUint32 i;
00413     if (object->numInstances == 0) {
00414        return (nssCryptokiObject **)NULL;
00415     }
00416     nssPKIObject_Lock(object);
00417     instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 
00418                               object->numInstances + 1);
00419     if (instances) {
00420        for (i=0; i<object->numInstances; i++) {
00421            instances[i] = nssCryptokiObject_Clone(object->instances[i]);
00422        }
00423     }
00424     nssPKIObject_Unlock(object);
00425     return instances;
00426 }
00427 #endif
00428 
00429 NSS_IMPLEMENT void
00430 nssCertificateArray_Destroy (
00431   NSSCertificate **certs
00432 )
00433 {
00434     if (certs) {
00435        NSSCertificate **certp;
00436        for (certp = certs; *certp; certp++) {
00437 #ifdef NSS_3_4_CODE
00438            if ((*certp)->decoding) {
00439               CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
00440               if (cc) {
00441                   CERT_DestroyCertificate(cc);
00442               }
00443               continue;
00444            }
00445 #endif
00446            nssCertificate_Destroy(*certp);
00447        }
00448        nss_ZFreeIf(certs);
00449     }
00450 }
00451 
00452 NSS_IMPLEMENT void
00453 NSSCertificateArray_Destroy (
00454   NSSCertificate **certs
00455 )
00456 {
00457     nssCertificateArray_Destroy(certs);
00458 }
00459 
00460 NSS_IMPLEMENT NSSCertificate **
00461 nssCertificateArray_Join (
00462   NSSCertificate **certs1,
00463   NSSCertificate **certs2
00464 )
00465 {
00466     if (certs1 && certs2) {
00467        NSSCertificate **certs, **cp;
00468        PRUint32 count = 0;
00469        PRUint32 count1 = 0;
00470        cp = certs1;
00471        while (*cp++) count1++;
00472        count = count1;
00473        cp = certs2;
00474        while (*cp++) count++;
00475        certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
00476        if (!certs) {
00477            nss_ZFreeIf(certs1);
00478            nss_ZFreeIf(certs2);
00479            return (NSSCertificate **)NULL;
00480        }
00481        for (cp = certs2; *cp; cp++, count1++) {
00482            certs[count1] = *cp;
00483        }
00484        nss_ZFreeIf(certs2);
00485        return certs;
00486     } else if (certs1) {
00487        return certs1;
00488     } else {
00489        return certs2;
00490     }
00491 }
00492 
00493 NSS_IMPLEMENT NSSCertificate * 
00494 nssCertificateArray_FindBestCertificate (
00495   NSSCertificate **certs, 
00496   NSSTime *timeOpt,
00497   const NSSUsage *usage,
00498   NSSPolicies *policiesOpt
00499 )
00500 {
00501     NSSCertificate *bestCert = NULL;
00502     NSSTime *time, sTime;
00503     PRBool haveUsageMatch = PR_FALSE;
00504     PRBool thisCertMatches;
00505 
00506     if (timeOpt) {
00507        time = timeOpt;
00508     } else {
00509        NSSTime_Now(&sTime);
00510        time = &sTime;
00511     }
00512     if (!certs) {
00513        return (NSSCertificate *)NULL;
00514     }
00515     for (; *certs; certs++) {
00516        nssDecodedCert *dc, *bestdc;
00517        NSSCertificate *c = *certs;
00518        dc = nssCertificate_GetDecoding(c);
00519        if (!dc) continue;
00520        thisCertMatches = dc->matchUsage(dc, usage);
00521        if (!bestCert) {
00522            /* always take the first cert, but remember whether or not
00523             * the usage matched 
00524             */
00525            bestCert = nssCertificate_AddRef(c);
00526            haveUsageMatch = thisCertMatches;
00527            continue;
00528        } else {
00529            if (haveUsageMatch && !thisCertMatches) {
00530               /* if already have a cert for this usage, and if this cert 
00531                * doesn't have the correct usage, continue
00532                */
00533               continue;
00534            } else if (!haveUsageMatch && thisCertMatches) {
00535               /* this one does match usage, replace the other */
00536               nssCertificate_Destroy(bestCert);
00537               bestCert = nssCertificate_AddRef(c);
00538               haveUsageMatch = PR_TRUE;
00539               continue;
00540            }
00541            /* this cert match as well as any cert we've found so far, 
00542             * defer to time/policies 
00543             * */
00544        }
00545        bestdc = nssCertificate_GetDecoding(bestCert);
00546        /* time */
00547        if (bestdc->isValidAtTime(bestdc, time)) {
00548            /* The current best cert is valid at time */
00549            if (!dc->isValidAtTime(dc, time)) {
00550               /* If the new cert isn't valid at time, it's not better */
00551               continue;
00552            }
00553        } else {
00554            /* The current best cert is not valid at time */
00555            if (dc->isValidAtTime(dc, time)) {
00556               /* If the new cert is valid at time, it's better */
00557               nssCertificate_Destroy(bestCert);
00558               bestCert = nssCertificate_AddRef(c);
00559            }
00560        }
00561        /* either they are both valid at time, or neither valid; 
00562         * take the newer one
00563         */
00564        if (!bestdc->isNewerThan(bestdc, dc)) {
00565            nssCertificate_Destroy(bestCert);
00566            bestCert = nssCertificate_AddRef(c);
00567        }
00568        /* policies */
00569        /* XXX later -- defer to policies */
00570     }
00571     return bestCert;
00572 }
00573 
00574 NSS_IMPLEMENT PRStatus
00575 nssCertificateArray_Traverse (
00576   NSSCertificate **certs,
00577   PRStatus (* callback)(NSSCertificate *c, void *arg),
00578   void *arg
00579 )
00580 {
00581     PRStatus status = PR_SUCCESS;
00582     if (certs) {
00583        NSSCertificate **certp;
00584        for (certp = certs; *certp; certp++) {
00585            status = (*callback)(*certp, arg);
00586            if (status != PR_SUCCESS) {
00587               break;
00588            }
00589        }
00590     }
00591     return status;
00592 }
00593 
00594 
00595 NSS_IMPLEMENT void
00596 nssCRLArray_Destroy (
00597   NSSCRL **crls
00598 )
00599 {
00600     if (crls) {
00601        NSSCRL **crlp;
00602        for (crlp = crls; *crlp; crlp++) {
00603            nssCRL_Destroy(*crlp);
00604        }
00605        nss_ZFreeIf(crls);
00606     }
00607 }
00608 
00609 /*
00610  * Object collections
00611  */
00612 
00613 typedef enum
00614 {
00615   pkiObjectType_Certificate = 0,
00616   pkiObjectType_CRL = 1,
00617   pkiObjectType_PrivateKey = 2,
00618   pkiObjectType_PublicKey = 3
00619 } pkiObjectType;
00620 
00621 /* Each object is defined by a set of items that uniquely identify it.
00622  * Here are the uid sets:
00623  *
00624  * NSSCertificate ==>  { issuer, serial }
00625  * NSSPrivateKey
00626  *         (RSA) ==> { modulus, public exponent }
00627  *
00628  */
00629 #define MAX_ITEMS_FOR_UID 2
00630 
00631 /* pkiObjectCollectionNode
00632  *
00633  * A node in the collection is the set of unique identifiers for a single
00634  * object, along with either the actual object or a proto-object.
00635  */
00636 typedef struct
00637 {
00638   PRCList link;
00639   PRBool haveObject;
00640   nssPKIObject *object;
00641   NSSItem uid[MAX_ITEMS_FOR_UID];
00642 } 
00643 pkiObjectCollectionNode;
00644 
00645 /* nssPKIObjectCollection
00646  *
00647  * The collection is the set of all objects, plus the interfaces needed
00648  * to manage the objects.
00649  *
00650  */
00651 struct nssPKIObjectCollectionStr
00652 {
00653   NSSArena *arena;
00654   NSSTrustDomain *td;
00655   NSSCryptoContext *cc;
00656   PRCList head; /* list of pkiObjectCollectionNode's */
00657   PRUint32 size;
00658   pkiObjectType objectType;
00659   void           (*      destroyObject)(nssPKIObject *o);
00660   PRStatus       (*   getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
00661   PRStatus       (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 
00662                                         NSSArena *arena);
00663   nssPKIObject * (*       createObject)(nssPKIObject *o);
00664   nssPKILockType lockType; /* type of lock to use for new proto-objects */
00665 };
00666 
00667 static nssPKIObjectCollection *
00668 nssPKIObjectCollection_Create (
00669   NSSTrustDomain *td,
00670   NSSCryptoContext *ccOpt,
00671   nssPKILockType lockType
00672 )
00673 {
00674     NSSArena *arena;
00675     nssPKIObjectCollection *rvCollection = NULL;
00676     arena = nssArena_Create();
00677     if (!arena) {
00678        return (nssPKIObjectCollection *)NULL;
00679     }
00680     rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
00681     if (!rvCollection) {
00682        goto loser;
00683     }
00684     PR_INIT_CLIST(&rvCollection->head);
00685     rvCollection->arena = arena;
00686     rvCollection->td = td; /* XXX */
00687     rvCollection->cc = ccOpt;
00688     rvCollection->lockType = lockType;
00689     return rvCollection;
00690 loser:
00691     nssArena_Destroy(arena);
00692     return (nssPKIObjectCollection *)NULL;
00693 }
00694 
00695 NSS_IMPLEMENT void
00696 nssPKIObjectCollection_Destroy (
00697   nssPKIObjectCollection *collection
00698 )
00699 {
00700     if (collection) {
00701        PRCList *link;
00702        pkiObjectCollectionNode *node;
00703        /* first destroy any objects in the collection */
00704        link = PR_NEXT_LINK(&collection->head);
00705        while (link != &collection->head) {
00706            node = (pkiObjectCollectionNode *)link;
00707            if (node->haveObject) {
00708               (*collection->destroyObject)(node->object);
00709            } else {
00710               nssPKIObject_Destroy(node->object);
00711            }
00712            link = PR_NEXT_LINK(link);
00713        }
00714        /* then destroy it */
00715        nssArena_Destroy(collection->arena);
00716     }
00717 }
00718 
00719 NSS_IMPLEMENT PRUint32
00720 nssPKIObjectCollection_Count (
00721   nssPKIObjectCollection *collection
00722 )
00723 {
00724     return collection->size;
00725 }
00726 
00727 NSS_IMPLEMENT PRStatus
00728 nssPKIObjectCollection_AddObject (
00729   nssPKIObjectCollection *collection,
00730   nssPKIObject *object
00731 )
00732 {
00733     pkiObjectCollectionNode *node;
00734     node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
00735     if (!node) {
00736        return PR_FAILURE;
00737     }
00738     node->haveObject = PR_TRUE;
00739     node->object = nssPKIObject_AddRef(object);
00740     (*collection->getUIDFromObject)(object, node->uid);
00741     PR_INIT_CLIST(&node->link);
00742     PR_INSERT_BEFORE(&node->link, &collection->head);
00743     collection->size++;
00744     return PR_SUCCESS;
00745 }
00746 
00747 static pkiObjectCollectionNode *
00748 find_instance_in_collection (
00749   nssPKIObjectCollection *collection,
00750   nssCryptokiObject *instance
00751 )
00752 {
00753     PRCList *link;
00754     pkiObjectCollectionNode *node;
00755     link = PR_NEXT_LINK(&collection->head);
00756     while (link != &collection->head) {
00757        node = (pkiObjectCollectionNode *)link;
00758        if (nssPKIObject_HasInstance(node->object, instance)) {
00759            return node;
00760        }
00761        link = PR_NEXT_LINK(link);
00762     }
00763     return (pkiObjectCollectionNode *)NULL;
00764 }
00765 
00766 static pkiObjectCollectionNode *
00767 find_object_in_collection (
00768   nssPKIObjectCollection *collection,
00769   NSSItem *uid
00770 )
00771 {
00772     PRUint32 i;
00773     PRStatus status;
00774     PRCList *link;
00775     pkiObjectCollectionNode *node;
00776     link = PR_NEXT_LINK(&collection->head);
00777     while (link != &collection->head) {
00778        node = (pkiObjectCollectionNode *)link;
00779        for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
00780            if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
00781               break;
00782            }
00783        }
00784        if (i == MAX_ITEMS_FOR_UID) {
00785            return node;
00786        }
00787        link = PR_NEXT_LINK(link);
00788     }
00789     return (pkiObjectCollectionNode *)NULL;
00790 }
00791 
00792 static pkiObjectCollectionNode *
00793 add_object_instance (
00794   nssPKIObjectCollection *collection,
00795   nssCryptokiObject *instance,
00796   PRBool *foundIt
00797 )
00798 {
00799     PRUint32 i;
00800     PRStatus status;
00801     pkiObjectCollectionNode *node;
00802     nssArenaMark *mark = NULL;
00803     NSSItem uid[MAX_ITEMS_FOR_UID];
00804     nsslibc_memset(uid, 0, sizeof uid);
00805     /* The list is traversed twice, first (here) looking to match the
00806      * { token, handle } tuple, and if that is not found, below a search
00807      * for unique identifier is done.  Here, a match means this exact object
00808      * instance is already in the collection, and we have nothing to do.
00809      */
00810     *foundIt = PR_FALSE;
00811     node = find_instance_in_collection(collection, instance);
00812     if (node) {
00813        /* The collection is assumed to take over the instance.  Since we
00814         * are not using it, it must be destroyed.
00815         */
00816        nssCryptokiObject_Destroy(instance);
00817        *foundIt = PR_TRUE;
00818        return node;
00819     }
00820     mark = nssArena_Mark(collection->arena);
00821     if (!mark) {
00822        goto loser;
00823     }
00824     status = (*collection->getUIDFromInstance)(instance, uid, 
00825                                                collection->arena);
00826     if (status != PR_SUCCESS) {
00827        goto loser;
00828     }
00829     /* Search for unique identifier.  A match here means the object exists 
00830      * in the collection, but does not have this instance, so the instance 
00831      * needs to be added.
00832      */
00833     node = find_object_in_collection(collection, uid);
00834     if (node) {
00835        /* This is an object with multiple instances */
00836        status = nssPKIObject_AddInstance(node->object, instance);
00837     } else {
00838        /* This is a completely new object.  Create a node for it. */
00839        node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
00840        if (!node) {
00841            goto loser;
00842        }
00843        node->object = nssPKIObject_Create(NULL, instance, 
00844                                           collection->td, collection->cc,
00845                                            collection->lockType);
00846        if (!node->object) {
00847            goto loser;
00848        }
00849        for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
00850            node->uid[i] = uid[i];
00851        }
00852        node->haveObject = PR_FALSE;
00853        PR_INIT_CLIST(&node->link);
00854        PR_INSERT_BEFORE(&node->link, &collection->head);
00855        collection->size++;
00856        status = PR_SUCCESS;
00857     }
00858     nssArena_Unmark(collection->arena, mark);
00859     return node;
00860 loser:
00861     if (mark) {
00862        nssArena_Release(collection->arena, mark);
00863     }
00864     nssCryptokiObject_Destroy(instance);
00865     return (pkiObjectCollectionNode *)NULL;
00866 }
00867 
00868 NSS_IMPLEMENT PRStatus
00869 nssPKIObjectCollection_AddInstances (
00870   nssPKIObjectCollection *collection,
00871   nssCryptokiObject **instances,
00872   PRUint32 numInstances
00873 )
00874 {
00875     PRStatus status = PR_SUCCESS;
00876     PRUint32 i = 0;
00877     PRBool foundIt;
00878     pkiObjectCollectionNode *node;
00879     if (instances) {
00880        for (; *instances; instances++, i++) {
00881            if (numInstances > 0 && i == numInstances) {
00882               break;
00883            }
00884            if (status == PR_SUCCESS) {
00885               node = add_object_instance(collection, *instances, &foundIt);
00886               if (node == NULL) {
00887                   /* add_object_instance freed the current instance */
00888                   /* free the remaining instances */
00889                   status = PR_FAILURE;
00890               }
00891            } else {
00892               nssCryptokiObject_Destroy(*instances);
00893            }
00894        }
00895     }
00896     return status;
00897 }
00898 
00899 static void
00900 nssPKIObjectCollection_RemoveNode (
00901    nssPKIObjectCollection *collection,
00902    pkiObjectCollectionNode *node
00903 )
00904 {
00905     PR_REMOVE_LINK(&node->link); 
00906     collection->size--;
00907 }
00908 
00909 static PRStatus
00910 nssPKIObjectCollection_GetObjects (
00911   nssPKIObjectCollection *collection,
00912   nssPKIObject **rvObjects,
00913   PRUint32 rvSize
00914 )
00915 {
00916     PRUint32 i = 0;
00917     PRCList *link = PR_NEXT_LINK(&collection->head);
00918     pkiObjectCollectionNode *node;
00919     int error=0;
00920     while ((i < rvSize) && (link != &collection->head)) {
00921        node = (pkiObjectCollectionNode *)link;
00922        if (!node->haveObject) {
00923            /* Convert the proto-object to an object */
00924            node->object = (*collection->createObject)(node->object);
00925            if (!node->object) {
00926               link = PR_NEXT_LINK(link);
00927               /*remove bogus object from list*/
00928               nssPKIObjectCollection_RemoveNode(collection,node);
00929               error++;
00930               continue;
00931            }
00932            node->haveObject = PR_TRUE;
00933        }
00934        rvObjects[i++] = nssPKIObject_AddRef(node->object);
00935        link = PR_NEXT_LINK(link);
00936     }
00937     if (!error && *rvObjects == NULL) {
00938        nss_SetError(NSS_ERROR_NOT_FOUND);
00939     }
00940     return PR_SUCCESS;
00941 }
00942 
00943 NSS_IMPLEMENT PRStatus
00944 nssPKIObjectCollection_Traverse (
00945   nssPKIObjectCollection *collection,
00946   nssPKIObjectCallback *callback
00947 )
00948 {
00949     PRStatus status;
00950     PRCList *link = PR_NEXT_LINK(&collection->head);
00951     pkiObjectCollectionNode *node;
00952     while (link != &collection->head) {
00953        node = (pkiObjectCollectionNode *)link;
00954        if (!node->haveObject) {
00955            node->object = (*collection->createObject)(node->object);
00956            if (!node->object) {
00957               link = PR_NEXT_LINK(link);
00958               /*remove bogus object from list*/
00959               nssPKIObjectCollection_RemoveNode(collection,node);
00960               continue;
00961            }
00962            node->haveObject = PR_TRUE;
00963        }
00964        switch (collection->objectType) {
00965        case pkiObjectType_Certificate: 
00966            status = (*callback->func.cert)((NSSCertificate *)node->object, 
00967                                            callback->arg);
00968            break;
00969        case pkiObjectType_CRL: 
00970            status = (*callback->func.crl)((NSSCRL *)node->object, 
00971                                           callback->arg);
00972            break;
00973        case pkiObjectType_PrivateKey: 
00974            status = (*callback->func.pvkey)((NSSPrivateKey *)node->object, 
00975                                             callback->arg);
00976            break;
00977        case pkiObjectType_PublicKey: 
00978            status = (*callback->func.pbkey)((NSSPublicKey *)node->object, 
00979                                             callback->arg);
00980            break;
00981        }
00982        link = PR_NEXT_LINK(link);
00983     }
00984     return PR_SUCCESS;
00985 }
00986 
00987 NSS_IMPLEMENT PRStatus
00988 nssPKIObjectCollection_AddInstanceAsObject (
00989   nssPKIObjectCollection *collection,
00990   nssCryptokiObject *instance
00991 )
00992 {
00993     pkiObjectCollectionNode *node;
00994     PRBool foundIt;
00995     node = add_object_instance(collection, instance, &foundIt);
00996     if (node == NULL) {
00997        return PR_FAILURE;
00998     }
00999     if (!node->haveObject) {
01000        node->object = (*collection->createObject)(node->object);
01001        if (!node->object) {
01002            /*remove bogus object from list*/
01003            nssPKIObjectCollection_RemoveNode(collection,node);
01004            return PR_FAILURE;
01005        }
01006        node->haveObject = PR_TRUE;
01007     }
01008 #ifdef NSS_3_4_CODE
01009     else if (!foundIt) {
01010        /* The instance was added to a pre-existing node.  This
01011         * function is *only* being used for certificates, and having
01012         * multiple instances of certs in 3.X requires updating the
01013         * CERTCertificate.
01014         * But only do it if it was a new instance!!!  If the same instance
01015         * is encountered, we set *foundIt to true.  Detect that here and
01016         * ignore it.
01017         */
01018        STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
01019     }
01020 #endif
01021     return PR_SUCCESS;
01022 }
01023 
01024 /*
01025  * Certificate collections
01026  */
01027 
01028 static void
01029 cert_destroyObject(nssPKIObject *o)
01030 {
01031     NSSCertificate *c = (NSSCertificate *)o;
01032 #ifdef NSS_3_4_CODE
01033     if (c->decoding) {
01034        CERTCertificate *cc = STAN_GetCERTCertificate(c);
01035        if (cc) {
01036            CERT_DestroyCertificate(cc);
01037            return;
01038        } /* else destroy it as NSSCertificate below */
01039     }
01040 #endif
01041     nssCertificate_Destroy(c);
01042 }
01043 
01044 static PRStatus
01045 cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
01046 {
01047     NSSCertificate *c = (NSSCertificate *)o;
01048 #ifdef NSS_3_4_CODE
01049     /* The builtins are still returning decoded serial numbers.  Until
01050      * this compatibility issue is resolved, use the full DER of the
01051      * cert to uniquely identify it.
01052      */
01053     NSSDER *derCert;
01054     derCert = nssCertificate_GetEncoding(c);
01055     uid[0].data = NULL; uid[0].size = 0;
01056     uid[1].data = NULL; uid[1].size = 0;
01057     if (derCert != NULL) {
01058        uid[0] = *derCert;
01059     }
01060 #else
01061     NSSDER *issuer, *serial;
01062     issuer = nssCertificate_GetIssuer(c);
01063     serial = nssCertificate_GetSerialNumber(c);
01064     uid[0] = *issuer;
01065     uid[1] = *serial;
01066 #endif /* NSS_3_4_CODE */
01067     return PR_SUCCESS;
01068 }
01069 
01070 static PRStatus
01071 cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
01072                         NSSArena *arena)
01073 {
01074 #ifdef NSS_3_4_CODE
01075     /* The builtins are still returning decoded serial numbers.  Until
01076      * this compatibility issue is resolved, use the full DER of the
01077      * cert to uniquely identify it.
01078      */
01079     uid[1].data = NULL; uid[1].size = 0;
01080     return nssCryptokiCertificate_GetAttributes(instance,
01081                                                 NULL,  /* XXX sessionOpt */
01082                                                 arena, /* arena    */
01083                                                 NULL,  /* type     */
01084                                                 NULL,  /* id       */
01085                                                 &uid[0], /* encoding */
01086                                                 NULL,  /* issuer   */
01087                                                 NULL,  /* serial   */
01088                                                 NULL);  /* subject  */
01089 #else
01090     return nssCryptokiCertificate_GetAttributes(instance,
01091                                                 NULL,  /* XXX sessionOpt */
01092                                                 arena, /* arena    */
01093                                                 NULL,  /* type     */
01094                                                 NULL,  /* id       */
01095                                                 NULL,  /* encoding */
01096                                                 &uid[0], /* issuer */
01097                                                 &uid[1], /* serial */
01098                                                 NULL);  /* subject  */
01099 #endif /* NSS_3_4_CODE */
01100 }
01101 
01102 static nssPKIObject *
01103 cert_createObject(nssPKIObject *o)
01104 {
01105     NSSCertificate *cert;
01106     cert = nssCertificate_Create(o);
01107 #ifdef NSS_3_4_CODE
01108 /*    if (STAN_GetCERTCertificate(cert) == NULL) {
01109        nssCertificate_Destroy(cert);
01110        return (nssPKIObject *)NULL;
01111     } */
01112     /* In 3.4, have to maintain uniqueness of cert pointers by caching all
01113      * certs.  Cache the cert here, before returning.  If it is already
01114      * cached, take the cached entry.
01115      */
01116     {
01117        NSSTrustDomain *td = o->trustDomain;
01118        nssTrustDomain_AddCertsToCache(td, &cert, 1);
01119     }
01120 #endif
01121     return (nssPKIObject *)cert;
01122 }
01123 
01124 NSS_IMPLEMENT nssPKIObjectCollection *
01125 nssCertificateCollection_Create (
01126   NSSTrustDomain *td,
01127   NSSCertificate **certsOpt
01128 )
01129 {
01130     PRStatus status;
01131     nssPKIObjectCollection *collection;
01132     collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
01133     collection->objectType = pkiObjectType_Certificate;
01134     collection->destroyObject = cert_destroyObject;
01135     collection->getUIDFromObject = cert_getUIDFromObject;
01136     collection->getUIDFromInstance = cert_getUIDFromInstance;
01137     collection->createObject = cert_createObject;
01138     if (certsOpt) {
01139        for (; *certsOpt; certsOpt++) {
01140            nssPKIObject *object = (nssPKIObject *)(*certsOpt);
01141            status = nssPKIObjectCollection_AddObject(collection, object);
01142        }
01143     }
01144     return collection;
01145 }
01146 
01147 NSS_IMPLEMENT NSSCertificate **
01148 nssPKIObjectCollection_GetCertificates (
01149   nssPKIObjectCollection *collection,
01150   NSSCertificate **rvOpt,
01151   PRUint32 maximumOpt,
01152   NSSArena *arenaOpt
01153 )
01154 {
01155     PRStatus status;
01156     PRUint32 rvSize;
01157     PRBool allocated = PR_FALSE;
01158     if (collection->size == 0) {
01159        return (NSSCertificate **)NULL;
01160     }
01161     if (maximumOpt == 0) {
01162        rvSize = collection->size;
01163     } else {
01164        rvSize = PR_MIN(collection->size, maximumOpt);
01165     }
01166     if (!rvOpt) {
01167        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
01168        if (!rvOpt) {
01169            return (NSSCertificate **)NULL;
01170        }
01171        allocated = PR_TRUE;
01172     }
01173     status = nssPKIObjectCollection_GetObjects(collection, 
01174                                                (nssPKIObject **)rvOpt, 
01175                                                rvSize);
01176     if (status != PR_SUCCESS) {
01177        if (allocated) {
01178            nss_ZFreeIf(rvOpt);
01179        }
01180        return (NSSCertificate **)NULL;
01181     }
01182     return rvOpt;
01183 }
01184 
01185 /*
01186  * CRL/KRL collections
01187  */
01188 
01189 static void
01190 crl_destroyObject(nssPKIObject *o)
01191 {
01192     NSSCRL *crl = (NSSCRL *)o;
01193     nssCRL_Destroy(crl);
01194 }
01195 
01196 static PRStatus
01197 crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
01198 {
01199     NSSCRL *crl = (NSSCRL *)o;
01200     NSSDER *encoding;
01201     encoding = nssCRL_GetEncoding(crl);
01202     uid[0] = *encoding;
01203     uid[1].data = NULL; uid[1].size = 0;
01204     return PR_SUCCESS;
01205 }
01206 
01207 static PRStatus
01208 crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
01209                        NSSArena *arena)
01210 {
01211     return nssCryptokiCRL_GetAttributes(instance,
01212                                         NULL,    /* XXX sessionOpt */
01213                                         arena,   /* arena    */
01214                                         &uid[0], /* encoding */
01215                                         NULL,    /* subject  */
01216                                         NULL,    /* class    */
01217                                         NULL,    /* url      */
01218                                         NULL);   /* isKRL    */
01219 }
01220 
01221 static nssPKIObject *
01222 crl_createObject(nssPKIObject *o)
01223 {
01224     return (nssPKIObject *)nssCRL_Create(o);
01225 }
01226 
01227 NSS_IMPLEMENT nssPKIObjectCollection *
01228 nssCRLCollection_Create (
01229   NSSTrustDomain *td,
01230   NSSCRL **crlsOpt
01231 )
01232 {
01233     PRStatus status;
01234     nssPKIObjectCollection *collection;
01235     collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
01236     collection->objectType = pkiObjectType_CRL;
01237     collection->destroyObject = crl_destroyObject;
01238     collection->getUIDFromObject = crl_getUIDFromObject;
01239     collection->getUIDFromInstance = crl_getUIDFromInstance;
01240     collection->createObject = crl_createObject;
01241     if (crlsOpt) {
01242        for (; *crlsOpt; crlsOpt++) {
01243            nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
01244            status = nssPKIObjectCollection_AddObject(collection, object);
01245        }
01246     }
01247     return collection;
01248 }
01249 
01250 NSS_IMPLEMENT NSSCRL **
01251 nssPKIObjectCollection_GetCRLs (
01252   nssPKIObjectCollection *collection,
01253   NSSCRL **rvOpt,
01254   PRUint32 maximumOpt,
01255   NSSArena *arenaOpt
01256 )
01257 {
01258     PRStatus status;
01259     PRUint32 rvSize;
01260     PRBool allocated = PR_FALSE;
01261     if (collection->size == 0) {
01262        return (NSSCRL **)NULL;
01263     }
01264     if (maximumOpt == 0) {
01265        rvSize = collection->size;
01266     } else {
01267        rvSize = PR_MIN(collection->size, maximumOpt);
01268     }
01269     if (!rvOpt) {
01270        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
01271        if (!rvOpt) {
01272            return (NSSCRL **)NULL;
01273        }
01274        allocated = PR_TRUE;
01275     }
01276     status = nssPKIObjectCollection_GetObjects(collection, 
01277                                                (nssPKIObject **)rvOpt, 
01278                                                rvSize);
01279     if (status != PR_SUCCESS) {
01280        if (allocated) {
01281            nss_ZFreeIf(rvOpt);
01282        }
01283        return (NSSCRL **)NULL;
01284     }
01285     return rvOpt;
01286 }
01287 
01288 #ifdef PURE_STAN_BUILD
01289 /*
01290  * PrivateKey collections
01291  */
01292 
01293 static void
01294 privkey_destroyObject(nssPKIObject *o)
01295 {
01296     NSSPrivateKey *pvk = (NSSPrivateKey *)o;
01297     nssPrivateKey_Destroy(pvk);
01298 }
01299 
01300 static PRStatus
01301 privkey_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
01302 {
01303     NSSPrivateKey *pvk = (NSSPrivateKey *)o;
01304     NSSItem *id;
01305     id = nssPrivateKey_GetID(pvk);
01306     uid[0] = *id;
01307     return PR_SUCCESS;
01308 }
01309 
01310 static PRStatus
01311 privkey_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
01312                            NSSArena *arena)
01313 {
01314     return nssCryptokiPrivateKey_GetAttributes(instance,
01315                                                NULL,  /* XXX sessionOpt */
01316                                                arena,
01317                                                NULL, /* type */
01318                                                &uid[0]);
01319 }
01320 
01321 static nssPKIObject *
01322 privkey_createObject(nssPKIObject *o)
01323 {
01324     NSSPrivateKey *pvk;
01325     pvk = nssPrivateKey_Create(o);
01326     return (nssPKIObject *)pvk;
01327 }
01328 
01329 NSS_IMPLEMENT nssPKIObjectCollection *
01330 nssPrivateKeyCollection_Create (
01331   NSSTrustDomain *td,
01332   NSSPrivateKey **pvkOpt
01333 )
01334 {
01335     PRStatus status;
01336     nssPKIObjectCollection *collection;
01337     collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
01338     collection->objectType = pkiObjectType_PrivateKey;
01339     collection->destroyObject = privkey_destroyObject;
01340     collection->getUIDFromObject = privkey_getUIDFromObject;
01341     collection->getUIDFromInstance = privkey_getUIDFromInstance;
01342     collection->createObject = privkey_createObject;
01343     if (pvkOpt) {
01344        for (; *pvkOpt; pvkOpt++) {
01345            nssPKIObject *o = (nssPKIObject *)(*pvkOpt);
01346            status = nssPKIObjectCollection_AddObject(collection, o);
01347        }
01348     }
01349     return collection;
01350 }
01351 
01352 NSS_IMPLEMENT NSSPrivateKey **
01353 nssPKIObjectCollection_GetPrivateKeys (
01354   nssPKIObjectCollection *collection,
01355   NSSPrivateKey **rvOpt,
01356   PRUint32 maximumOpt,
01357   NSSArena *arenaOpt
01358 )
01359 {
01360     PRStatus status;
01361     PRUint32 rvSize;
01362     PRBool allocated = PR_FALSE;
01363     if (collection->size == 0) {
01364        return (NSSPrivateKey **)NULL;
01365     }
01366     if (maximumOpt == 0) {
01367        rvSize = collection->size;
01368     } else {
01369        rvSize = PR_MIN(collection->size, maximumOpt);
01370     }
01371     if (!rvOpt) {
01372        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSPrivateKey *, rvSize + 1);
01373        if (!rvOpt) {
01374            return (NSSPrivateKey **)NULL;
01375        }
01376        allocated = PR_TRUE;
01377     }
01378     status = nssPKIObjectCollection_GetObjects(collection, 
01379                                                (nssPKIObject **)rvOpt, 
01380                                                rvSize);
01381     if (status != PR_SUCCESS) {
01382        if (allocated) {
01383            nss_ZFreeIf(rvOpt);
01384        }
01385        return (NSSPrivateKey **)NULL;
01386     }
01387     return rvOpt;
01388 }
01389 
01390 /*
01391  * PublicKey collections
01392  */
01393 
01394 static void
01395 pubkey_destroyObject(nssPKIObject *o)
01396 {
01397     NSSPublicKey *pubk = (NSSPublicKey *)o;
01398     nssPublicKey_Destroy(pubk);
01399 }
01400 
01401 static PRStatus
01402 pubkey_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
01403 {
01404     NSSPublicKey *pubk = (NSSPublicKey *)o;
01405     NSSItem *id;
01406     id = nssPublicKey_GetID(pubk);
01407     uid[0] = *id;
01408     return PR_SUCCESS;
01409 }
01410 
01411 static PRStatus
01412 pubkey_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
01413                           NSSArena *arena)
01414 {
01415     return nssCryptokiPublicKey_GetAttributes(instance,
01416                                               NULL,  /* XXX sessionOpt */
01417                                               arena,
01418                                               NULL, /* type */
01419                                               &uid[0]);
01420 }
01421 
01422 static nssPKIObject *
01423 pubkey_createObject(nssPKIObject *o)
01424 {
01425     NSSPublicKey *pubk;
01426     pubk = nssPublicKey_Create(o);
01427     return (nssPKIObject *)pubk;
01428 }
01429 
01430 NSS_IMPLEMENT nssPKIObjectCollection *
01431 nssPublicKeyCollection_Create (
01432   NSSTrustDomain *td,
01433   NSSPublicKey **pubkOpt
01434 )
01435 {
01436     PRStatus status;
01437     nssPKIObjectCollection *collection;
01438     collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
01439     collection->objectType = pkiObjectType_PublicKey;
01440     collection->destroyObject = pubkey_destroyObject;
01441     collection->getUIDFromObject = pubkey_getUIDFromObject;
01442     collection->getUIDFromInstance = pubkey_getUIDFromInstance;
01443     collection->createObject = pubkey_createObject;
01444     if (pubkOpt) {
01445        for (; *pubkOpt; pubkOpt++) {
01446            nssPKIObject *o = (nssPKIObject *)(*pubkOpt);
01447            status = nssPKIObjectCollection_AddObject(collection, o);
01448        }
01449     }
01450     return collection;
01451 }
01452 
01453 NSS_IMPLEMENT NSSPublicKey **
01454 nssPKIObjectCollection_GetPublicKeys (
01455   nssPKIObjectCollection *collection,
01456   NSSPublicKey **rvOpt,
01457   PRUint32 maximumOpt,
01458   NSSArena *arenaOpt
01459 )
01460 {
01461     PRStatus status;
01462     PRUint32 rvSize;
01463     PRBool allocated = PR_FALSE;
01464     if (collection->size == 0) {
01465        return (NSSPublicKey **)NULL;
01466     }
01467     if (maximumOpt == 0) {
01468        rvSize = collection->size;
01469     } else {
01470        rvSize = PR_MIN(collection->size, maximumOpt);
01471     }
01472     if (!rvOpt) {
01473        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSPublicKey *, rvSize + 1);
01474        if (!rvOpt) {
01475            return (NSSPublicKey **)NULL;
01476        }
01477        allocated = PR_TRUE;
01478     }
01479     status = nssPKIObjectCollection_GetObjects(collection, 
01480                                                (nssPKIObject **)rvOpt, 
01481                                                rvSize);
01482     if (status != PR_SUCCESS) {
01483        if (allocated) {
01484            nss_ZFreeIf(rvOpt);
01485        }
01486        return (NSSPublicKey **)NULL;
01487     }
01488     return rvOpt;
01489 }
01490 #endif /* PURE_STAN_BUILD */
01491 
01492 /* how bad would it be to have a static now sitting around, updated whenever
01493  * this was called?  would avoid repeated allocs...
01494  */
01495 NSS_IMPLEMENT NSSTime *
01496 NSSTime_Now (
01497   NSSTime *timeOpt
01498 )
01499 {
01500     return NSSTime_SetPRTime(timeOpt, PR_Now());
01501 }
01502 
01503 NSS_IMPLEMENT NSSTime *
01504 NSSTime_SetPRTime (
01505   NSSTime *timeOpt,
01506   PRTime prTime
01507 )
01508 {
01509     NSSTime *rvTime;
01510     rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
01511     rvTime->prTime = prTime;
01512     return rvTime;
01513 }
01514 
01515 NSS_IMPLEMENT PRTime
01516 NSSTime_GetPRTime (
01517   NSSTime *time
01518 )
01519 {
01520   return time->prTime;
01521 }
01522