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.3 $ $Date: 2007/11/21 18:07:52 $";
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 #include "pki3hack.h"
00050 
00051 extern const NSSError NSS_ERROR_NOT_FOUND;
00052 
00053 NSS_IMPLEMENT void
00054 nssPKIObject_Lock(nssPKIObject * object)
00055 {
00056     switch (object->lockType) {
00057     case nssPKIMonitor:
00058         PZ_EnterMonitor(object->sync.mlock);
00059         break;
00060     case nssPKILock:
00061         PZ_Lock(object->sync.lock);
00062         break;
00063     default:
00064         PORT_Assert(0);
00065     }
00066 }
00067 
00068 NSS_IMPLEMENT void
00069 nssPKIObject_Unlock(nssPKIObject * object)
00070 {
00071     switch (object->lockType) {
00072     case nssPKIMonitor:
00073         PZ_ExitMonitor(object->sync.mlock);
00074         break;
00075     case nssPKILock:
00076         PZ_Unlock(object->sync.lock);
00077         break;
00078     default:
00079         PORT_Assert(0);
00080     }
00081 }
00082 
00083 NSS_IMPLEMENT PRStatus
00084 nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType)
00085 {
00086     object->lockType = lockType;
00087     switch (lockType) {
00088     case nssPKIMonitor:
00089         object->sync.mlock = PZ_NewMonitor(nssILockSSL);
00090         return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
00091     case nssPKILock:
00092         object->sync.lock = PZ_NewLock(nssILockSSL);
00093         return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
00094     default:
00095         PORT_Assert(0);
00096         return PR_FAILURE;
00097     }
00098 }
00099 
00100 NSS_IMPLEMENT void
00101 nssPKIObject_DestroyLock(nssPKIObject * object)
00102 {
00103     switch (object->lockType) {
00104     case nssPKIMonitor:
00105         PZ_DestroyMonitor(object->sync.mlock);
00106         object->sync.mlock = NULL;
00107         break;
00108     case nssPKILock:
00109         PZ_DestroyLock(object->sync.lock);
00110         object->sync.lock = NULL;
00111         break;
00112     default:
00113         PORT_Assert(0);
00114     }
00115 }
00116 
00117 
00118 
00119 NSS_IMPLEMENT nssPKIObject *
00120 nssPKIObject_Create (
00121   NSSArena *arenaOpt,
00122   nssCryptokiObject *instanceOpt,
00123   NSSTrustDomain *td,
00124   NSSCryptoContext *cc,
00125   nssPKILockType lockType
00126 )
00127 {
00128     NSSArena *arena;
00129     nssArenaMark *mark = NULL;
00130     nssPKIObject *object;
00131     if (arenaOpt) {
00132        arena = arenaOpt;
00133        mark = nssArena_Mark(arena);
00134     } else {
00135        arena = nssArena_Create();
00136        if (!arena) {
00137            return (nssPKIObject *)NULL;
00138        }
00139     }
00140     object = nss_ZNEW(arena, nssPKIObject);
00141     if (!object) {
00142        goto loser;
00143     }
00144     object->arena = arena;
00145     object->trustDomain = td; /* XXX */
00146     object->cryptoContext = cc;
00147     if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
00148        goto loser;
00149     }
00150     if (instanceOpt) {
00151        if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
00152            goto loser;
00153        }
00154     }
00155     PR_AtomicIncrement(&object->refCount);
00156     if (mark) {
00157        nssArena_Unmark(arena, mark);
00158     }
00159     return object;
00160 loser:
00161     if (mark) {
00162        nssArena_Release(arena, mark);
00163     } else {
00164        nssArena_Destroy(arena);
00165     }
00166     return (nssPKIObject *)NULL;
00167 }
00168 
00169 NSS_IMPLEMENT PRBool
00170 nssPKIObject_Destroy (
00171   nssPKIObject *object
00172 )
00173 {
00174     PRUint32 i;
00175     PR_ASSERT(object->refCount > 0);
00176     if (PR_AtomicDecrement(&object->refCount) == 0) {
00177        for (i=0; i<object->numInstances; i++) {
00178            nssCryptokiObject_Destroy(object->instances[i]);
00179        }
00180        nssPKIObject_DestroyLock(object);
00181        nssArena_Destroy(object->arena);
00182        return PR_TRUE;
00183     }
00184     return PR_FALSE;
00185 }
00186 
00187 NSS_IMPLEMENT nssPKIObject *
00188 nssPKIObject_AddRef (
00189   nssPKIObject *object
00190 )
00191 {
00192     PR_AtomicIncrement(&object->refCount);
00193     return object;
00194 }
00195 
00196 NSS_IMPLEMENT PRStatus
00197 nssPKIObject_AddInstance (
00198   nssPKIObject *object,
00199   nssCryptokiObject *instance
00200 )
00201 {
00202     nssPKIObject_Lock(object);
00203     if (object->numInstances == 0) {
00204        object->instances = nss_ZNEWARRAY(object->arena,
00205                                          nssCryptokiObject *,
00206                                          object->numInstances + 1);
00207     } else {
00208        PRUint32 i;
00209        for (i=0; i<object->numInstances; i++) {
00210            if (nssCryptokiObject_Equal(object->instances[i], instance)) {
00211               nssPKIObject_Unlock(object);
00212               if (instance->label) {
00213                   if (!object->instances[i]->label ||
00214                       !nssUTF8_Equal(instance->label,
00215                                      object->instances[i]->label, NULL))
00216                   {
00217                      /* Either the old instance did not have a label,
00218                       * or the label has changed.
00219                       */
00220                      nss_ZFreeIf(object->instances[i]->label);
00221                      object->instances[i]->label = instance->label;
00222                      instance->label = NULL;
00223                   }
00224               } else if (object->instances[i]->label) {
00225                   /* The old label was removed */
00226                   nss_ZFreeIf(object->instances[i]->label);
00227                   object->instances[i]->label = NULL;
00228               }
00229               nssCryptokiObject_Destroy(instance);
00230               return PR_SUCCESS;
00231            }
00232        }
00233        object->instances = nss_ZREALLOCARRAY(object->instances,
00234                                              nssCryptokiObject *,
00235                                              object->numInstances + 1);
00236     }
00237     if (!object->instances) {
00238        nssPKIObject_Unlock(object);
00239        return PR_FAILURE;
00240     }
00241     object->instances[object->numInstances++] = instance;
00242     nssPKIObject_Unlock(object);
00243     return PR_SUCCESS;
00244 }
00245 
00246 NSS_IMPLEMENT PRBool
00247 nssPKIObject_HasInstance (
00248   nssPKIObject *object,
00249   nssCryptokiObject *instance
00250 )
00251 {
00252     PRUint32 i;
00253     PRBool hasIt = PR_FALSE;;
00254     nssPKIObject_Lock(object);
00255     for (i=0; i<object->numInstances; i++) {
00256        if (nssCryptokiObject_Equal(object->instances[i], instance)) {
00257            hasIt = PR_TRUE;
00258            break;
00259        }
00260     }
00261     nssPKIObject_Unlock(object);
00262     return hasIt;
00263 }
00264 
00265 NSS_IMPLEMENT PRStatus
00266 nssPKIObject_RemoveInstanceForToken (
00267   nssPKIObject *object,
00268   NSSToken *token
00269 )
00270 {
00271     PRUint32 i;
00272     nssCryptokiObject *instanceToRemove = NULL;
00273     nssPKIObject_Lock(object);
00274     if (object->numInstances == 0) {
00275        nssPKIObject_Unlock(object);
00276        return PR_SUCCESS;
00277     }
00278     for (i=0; i<object->numInstances; i++) {
00279        if (object->instances[i]->token == token) {
00280            instanceToRemove = object->instances[i];
00281            object->instances[i] = object->instances[object->numInstances-1];
00282            object->instances[object->numInstances-1] = NULL;
00283            break;
00284        }
00285     }
00286     if (--object->numInstances > 0) {
00287        nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
00288                                              nssCryptokiObject *,
00289                                              object->numInstances);
00290        if (instances) {
00291            object->instances = instances;
00292        }
00293     } else {
00294        nss_ZFreeIf(object->instances);
00295     }
00296     nssCryptokiObject_Destroy(instanceToRemove);
00297     nssPKIObject_Unlock(object);
00298     return PR_SUCCESS;
00299 }
00300 
00301 /* this needs more thought on what will happen when there are multiple
00302  * instances
00303  */
00304 NSS_IMPLEMENT PRStatus
00305 nssPKIObject_DeleteStoredObject (
00306   nssPKIObject *object,
00307   NSSCallback *uhh,
00308   PRBool isFriendly
00309 )
00310 {
00311     PRUint32 i, numNotDestroyed;
00312     PRStatus status = PR_SUCCESS;
00313     numNotDestroyed = 0;
00314     nssPKIObject_Lock(object);
00315     for (i=0; i<object->numInstances; i++) {
00316        nssCryptokiObject *instance = object->instances[i];
00317        status = nssToken_DeleteStoredObject(instance);
00318        object->instances[i] = NULL;
00319        if (status == PR_SUCCESS) {
00320            nssCryptokiObject_Destroy(instance);
00321        } else {
00322            object->instances[numNotDestroyed++] = instance;
00323        }
00324     }
00325     if (numNotDestroyed == 0) {
00326        nss_ZFreeIf(object->instances);
00327        object->numInstances = 0;
00328     } else {
00329        object->numInstances = numNotDestroyed;
00330     }
00331     nssPKIObject_Unlock(object);
00332     return status;
00333 }
00334 
00335 NSS_IMPLEMENT NSSToken **
00336 nssPKIObject_GetTokens (
00337   nssPKIObject *object,
00338   PRStatus *statusOpt
00339 )
00340 {
00341     NSSToken **tokens = NULL;
00342     nssPKIObject_Lock(object);
00343     if (object->numInstances > 0) {
00344        tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
00345        if (tokens) {
00346            PRUint32 i;
00347            for (i=0; i<object->numInstances; i++) {
00348               tokens[i] = nssToken_AddRef(object->instances[i]->token);
00349            }
00350        }
00351     }
00352     nssPKIObject_Unlock(object);
00353     if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */
00354     return tokens;
00355 }
00356 
00357 NSS_IMPLEMENT NSSUTF8 *
00358 nssPKIObject_GetNicknameForToken (
00359   nssPKIObject *object,
00360   NSSToken *tokenOpt
00361 )
00362 {
00363     PRUint32 i;
00364     NSSUTF8 *nickname = NULL;
00365     nssPKIObject_Lock(object);
00366     for (i=0; i<object->numInstances; i++) {
00367        if ((!tokenOpt && object->instances[i]->label) ||
00368            (object->instances[i]->token == tokenOpt)) 
00369        {
00370             /* XXX should be copy? safe as long as caller has reference */
00371            nickname = object->instances[i]->label; 
00372            break;
00373        }
00374     }
00375     nssPKIObject_Unlock(object);
00376     return nickname;
00377 }
00378 
00379 NSS_IMPLEMENT nssCryptokiObject **
00380 nssPKIObject_GetInstances (
00381   nssPKIObject *object
00382 )
00383 {
00384     nssCryptokiObject **instances = NULL;
00385     PRUint32 i;
00386     if (object->numInstances == 0) {
00387        return (nssCryptokiObject **)NULL;
00388     }
00389     nssPKIObject_Lock(object);
00390     instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 
00391                               object->numInstances + 1);
00392     if (instances) {
00393        for (i=0; i<object->numInstances; i++) {
00394            instances[i] = nssCryptokiObject_Clone(object->instances[i]);
00395        }
00396     }
00397     nssPKIObject_Unlock(object);
00398     return instances;
00399 }
00400 
00401 NSS_IMPLEMENT void
00402 nssCertificateArray_Destroy (
00403   NSSCertificate **certs
00404 )
00405 {
00406     if (certs) {
00407        NSSCertificate **certp;
00408        for (certp = certs; *certp; certp++) {
00409            if ((*certp)->decoding) {
00410               CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
00411               if (cc) {
00412                   CERT_DestroyCertificate(cc);
00413               }
00414               continue;
00415            }
00416            nssCertificate_Destroy(*certp);
00417        }
00418        nss_ZFreeIf(certs);
00419     }
00420 }
00421 
00422 NSS_IMPLEMENT void
00423 NSSCertificateArray_Destroy (
00424   NSSCertificate **certs
00425 )
00426 {
00427     nssCertificateArray_Destroy(certs);
00428 }
00429 
00430 NSS_IMPLEMENT NSSCertificate **
00431 nssCertificateArray_Join (
00432   NSSCertificate **certs1,
00433   NSSCertificate **certs2
00434 )
00435 {
00436     if (certs1 && certs2) {
00437        NSSCertificate **certs, **cp;
00438        PRUint32 count = 0;
00439        PRUint32 count1 = 0;
00440        cp = certs1;
00441        while (*cp++) count1++;
00442        count = count1;
00443        cp = certs2;
00444        while (*cp++) count++;
00445        certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
00446        if (!certs) {
00447            nss_ZFreeIf(certs1);
00448            nss_ZFreeIf(certs2);
00449            return (NSSCertificate **)NULL;
00450        }
00451        for (cp = certs2; *cp; cp++, count1++) {
00452            certs[count1] = *cp;
00453        }
00454        nss_ZFreeIf(certs2);
00455        return certs;
00456     } else if (certs1) {
00457        return certs1;
00458     } else {
00459        return certs2;
00460     }
00461 }
00462 
00463 NSS_IMPLEMENT NSSCertificate * 
00464 nssCertificateArray_FindBestCertificate (
00465   NSSCertificate **certs, 
00466   NSSTime *timeOpt,
00467   const NSSUsage *usage,
00468   NSSPolicies *policiesOpt
00469 )
00470 {
00471     NSSCertificate *bestCert = NULL;
00472     NSSTime *time, sTime;
00473     PRBool haveUsageMatch = PR_FALSE;
00474     PRBool thisCertMatches;
00475 
00476     if (timeOpt) {
00477        time = timeOpt;
00478     } else {
00479        NSSTime_Now(&sTime);
00480        time = &sTime;
00481     }
00482     if (!certs) {
00483        return (NSSCertificate *)NULL;
00484     }
00485     for (; *certs; certs++) {
00486        nssDecodedCert *dc, *bestdc;
00487        NSSCertificate *c = *certs;
00488        dc = nssCertificate_GetDecoding(c);
00489        if (!dc) continue;
00490        thisCertMatches = dc->matchUsage(dc, usage);
00491        if (!bestCert) {
00492            /* always take the first cert, but remember whether or not
00493             * the usage matched 
00494             */
00495            bestCert = nssCertificate_AddRef(c);
00496            haveUsageMatch = thisCertMatches;
00497            continue;
00498        } else {
00499            if (haveUsageMatch && !thisCertMatches) {
00500               /* if already have a cert for this usage, and if this cert 
00501                * doesn't have the correct usage, continue
00502                */
00503               continue;
00504            } else if (!haveUsageMatch && thisCertMatches) {
00505               /* this one does match usage, replace the other */
00506               nssCertificate_Destroy(bestCert);
00507               bestCert = nssCertificate_AddRef(c);
00508               haveUsageMatch = PR_TRUE;
00509               continue;
00510            }
00511            /* this cert match as well as any cert we've found so far, 
00512             * defer to time/policies 
00513             * */
00514        }
00515        bestdc = nssCertificate_GetDecoding(bestCert);
00516        /* time */
00517        if (bestdc->isValidAtTime(bestdc, time)) {
00518            /* The current best cert is valid at time */
00519            if (!dc->isValidAtTime(dc, time)) {
00520               /* If the new cert isn't valid at time, it's not better */
00521               continue;
00522            }
00523        } else {
00524            /* The current best cert is not valid at time */
00525            if (dc->isValidAtTime(dc, time)) {
00526               /* If the new cert is valid at time, it's better */
00527               nssCertificate_Destroy(bestCert);
00528               bestCert = nssCertificate_AddRef(c);
00529            }
00530        }
00531        /* either they are both valid at time, or neither valid; 
00532         * take the newer one
00533         */
00534        if (!bestdc->isNewerThan(bestdc, dc)) {
00535            nssCertificate_Destroy(bestCert);
00536            bestCert = nssCertificate_AddRef(c);
00537        }
00538        /* policies */
00539        /* XXX later -- defer to policies */
00540     }
00541     return bestCert;
00542 }
00543 
00544 NSS_IMPLEMENT PRStatus
00545 nssCertificateArray_Traverse (
00546   NSSCertificate **certs,
00547   PRStatus (* callback)(NSSCertificate *c, void *arg),
00548   void *arg
00549 )
00550 {
00551     PRStatus status = PR_SUCCESS;
00552     if (certs) {
00553        NSSCertificate **certp;
00554        for (certp = certs; *certp; certp++) {
00555            status = (*callback)(*certp, arg);
00556            if (status != PR_SUCCESS) {
00557               break;
00558            }
00559        }
00560     }
00561     return status;
00562 }
00563 
00564 
00565 NSS_IMPLEMENT void
00566 nssCRLArray_Destroy (
00567   NSSCRL **crls
00568 )
00569 {
00570     if (crls) {
00571        NSSCRL **crlp;
00572        for (crlp = crls; *crlp; crlp++) {
00573            nssCRL_Destroy(*crlp);
00574        }
00575        nss_ZFreeIf(crls);
00576     }
00577 }
00578 
00579 /*
00580  * Object collections
00581  */
00582 
00583 typedef enum
00584 {
00585   pkiObjectType_Certificate = 0,
00586   pkiObjectType_CRL = 1,
00587   pkiObjectType_PrivateKey = 2,
00588   pkiObjectType_PublicKey = 3
00589 } pkiObjectType;
00590 
00591 /* Each object is defined by a set of items that uniquely identify it.
00592  * Here are the uid sets:
00593  *
00594  * NSSCertificate ==>  { issuer, serial }
00595  * NSSPrivateKey
00596  *         (RSA) ==> { modulus, public exponent }
00597  *
00598  */
00599 #define MAX_ITEMS_FOR_UID 2
00600 
00601 /* pkiObjectCollectionNode
00602  *
00603  * A node in the collection is the set of unique identifiers for a single
00604  * object, along with either the actual object or a proto-object.
00605  */
00606 typedef struct
00607 {
00608   PRCList link;
00609   PRBool haveObject;
00610   nssPKIObject *object;
00611   NSSItem uid[MAX_ITEMS_FOR_UID];
00612 } 
00613 pkiObjectCollectionNode;
00614 
00615 /* nssPKIObjectCollection
00616  *
00617  * The collection is the set of all objects, plus the interfaces needed
00618  * to manage the objects.
00619  *
00620  */
00621 struct nssPKIObjectCollectionStr
00622 {
00623   NSSArena *arena;
00624   NSSTrustDomain *td;
00625   NSSCryptoContext *cc;
00626   PRCList head; /* list of pkiObjectCollectionNode's */
00627   PRUint32 size;
00628   pkiObjectType objectType;
00629   void           (*      destroyObject)(nssPKIObject *o);
00630   PRStatus       (*   getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
00631   PRStatus       (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 
00632                                         NSSArena *arena);
00633   nssPKIObject * (*       createObject)(nssPKIObject *o);
00634   nssPKILockType lockType; /* type of lock to use for new proto-objects */
00635 };
00636 
00637 static nssPKIObjectCollection *
00638 nssPKIObjectCollection_Create (
00639   NSSTrustDomain *td,
00640   NSSCryptoContext *ccOpt,
00641   nssPKILockType lockType
00642 )
00643 {
00644     NSSArena *arena;
00645     nssPKIObjectCollection *rvCollection = NULL;
00646     arena = nssArena_Create();
00647     if (!arena) {
00648        return (nssPKIObjectCollection *)NULL;
00649     }
00650     rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
00651     if (!rvCollection) {
00652        goto loser;
00653     }
00654     PR_INIT_CLIST(&rvCollection->head);
00655     rvCollection->arena = arena;
00656     rvCollection->td = td; /* XXX */
00657     rvCollection->cc = ccOpt;
00658     rvCollection->lockType = lockType;
00659     return rvCollection;
00660 loser:
00661     nssArena_Destroy(arena);
00662     return (nssPKIObjectCollection *)NULL;
00663 }
00664 
00665 NSS_IMPLEMENT void
00666 nssPKIObjectCollection_Destroy (
00667   nssPKIObjectCollection *collection
00668 )
00669 {
00670     if (collection) {
00671        PRCList *link;
00672        pkiObjectCollectionNode *node;
00673        /* first destroy any objects in the collection */
00674        link = PR_NEXT_LINK(&collection->head);
00675        while (link != &collection->head) {
00676            node = (pkiObjectCollectionNode *)link;
00677            if (node->haveObject) {
00678               (*collection->destroyObject)(node->object);
00679            } else {
00680               nssPKIObject_Destroy(node->object);
00681            }
00682            link = PR_NEXT_LINK(link);
00683        }
00684        /* then destroy it */
00685        nssArena_Destroy(collection->arena);
00686     }
00687 }
00688 
00689 NSS_IMPLEMENT PRUint32
00690 nssPKIObjectCollection_Count (
00691   nssPKIObjectCollection *collection
00692 )
00693 {
00694     return collection->size;
00695 }
00696 
00697 NSS_IMPLEMENT PRStatus
00698 nssPKIObjectCollection_AddObject (
00699   nssPKIObjectCollection *collection,
00700   nssPKIObject *object
00701 )
00702 {
00703     pkiObjectCollectionNode *node;
00704     node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
00705     if (!node) {
00706        return PR_FAILURE;
00707     }
00708     node->haveObject = PR_TRUE;
00709     node->object = nssPKIObject_AddRef(object);
00710     (*collection->getUIDFromObject)(object, node->uid);
00711     PR_INIT_CLIST(&node->link);
00712     PR_INSERT_BEFORE(&node->link, &collection->head);
00713     collection->size++;
00714     return PR_SUCCESS;
00715 }
00716 
00717 static pkiObjectCollectionNode *
00718 find_instance_in_collection (
00719   nssPKIObjectCollection *collection,
00720   nssCryptokiObject *instance
00721 )
00722 {
00723     PRCList *link;
00724     pkiObjectCollectionNode *node;
00725     link = PR_NEXT_LINK(&collection->head);
00726     while (link != &collection->head) {
00727        node = (pkiObjectCollectionNode *)link;
00728        if (nssPKIObject_HasInstance(node->object, instance)) {
00729            return node;
00730        }
00731        link = PR_NEXT_LINK(link);
00732     }
00733     return (pkiObjectCollectionNode *)NULL;
00734 }
00735 
00736 static pkiObjectCollectionNode *
00737 find_object_in_collection (
00738   nssPKIObjectCollection *collection,
00739   NSSItem *uid
00740 )
00741 {
00742     PRUint32 i;
00743     PRStatus status;
00744     PRCList *link;
00745     pkiObjectCollectionNode *node;
00746     link = PR_NEXT_LINK(&collection->head);
00747     while (link != &collection->head) {
00748        node = (pkiObjectCollectionNode *)link;
00749        for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
00750            if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
00751               break;
00752            }
00753        }
00754        if (i == MAX_ITEMS_FOR_UID) {
00755            return node;
00756        }
00757        link = PR_NEXT_LINK(link);
00758     }
00759     return (pkiObjectCollectionNode *)NULL;
00760 }
00761 
00762 static pkiObjectCollectionNode *
00763 add_object_instance (
00764   nssPKIObjectCollection *collection,
00765   nssCryptokiObject *instance,
00766   PRBool *foundIt
00767 )
00768 {
00769     PRUint32 i;
00770     PRStatus status;
00771     pkiObjectCollectionNode *node;
00772     nssArenaMark *mark = NULL;
00773     NSSItem uid[MAX_ITEMS_FOR_UID];
00774     nsslibc_memset(uid, 0, sizeof uid);
00775     /* The list is traversed twice, first (here) looking to match the
00776      * { token, handle } tuple, and if that is not found, below a search
00777      * for unique identifier is done.  Here, a match means this exact object
00778      * instance is already in the collection, and we have nothing to do.
00779      */
00780     *foundIt = PR_FALSE;
00781     node = find_instance_in_collection(collection, instance);
00782     if (node) {
00783        /* The collection is assumed to take over the instance.  Since we
00784         * are not using it, it must be destroyed.
00785         */
00786        nssCryptokiObject_Destroy(instance);
00787        *foundIt = PR_TRUE;
00788        return node;
00789     }
00790     mark = nssArena_Mark(collection->arena);
00791     if (!mark) {
00792        goto loser;
00793     }
00794     status = (*collection->getUIDFromInstance)(instance, uid, 
00795                                                collection->arena);
00796     if (status != PR_SUCCESS) {
00797        goto loser;
00798     }
00799     /* Search for unique identifier.  A match here means the object exists 
00800      * in the collection, but does not have this instance, so the instance 
00801      * needs to be added.
00802      */
00803     node = find_object_in_collection(collection, uid);
00804     if (node) {
00805        /* This is an object with multiple instances */
00806        status = nssPKIObject_AddInstance(node->object, instance);
00807     } else {
00808        /* This is a completely new object.  Create a node for it. */
00809        node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
00810        if (!node) {
00811            goto loser;
00812        }
00813        node->object = nssPKIObject_Create(NULL, instance, 
00814                                           collection->td, collection->cc,
00815                                            collection->lockType);
00816        if (!node->object) {
00817            goto loser;
00818        }
00819        for (i=0; i<MAX_ITEMS_FOR_UID; i++) {
00820            node->uid[i] = uid[i];
00821        }
00822        node->haveObject = PR_FALSE;
00823        PR_INIT_CLIST(&node->link);
00824        PR_INSERT_BEFORE(&node->link, &collection->head);
00825        collection->size++;
00826        status = PR_SUCCESS;
00827     }
00828     nssArena_Unmark(collection->arena, mark);
00829     return node;
00830 loser:
00831     if (mark) {
00832        nssArena_Release(collection->arena, mark);
00833     }
00834     nssCryptokiObject_Destroy(instance);
00835     return (pkiObjectCollectionNode *)NULL;
00836 }
00837 
00838 NSS_IMPLEMENT PRStatus
00839 nssPKIObjectCollection_AddInstances (
00840   nssPKIObjectCollection *collection,
00841   nssCryptokiObject **instances,
00842   PRUint32 numInstances
00843 )
00844 {
00845     PRStatus status = PR_SUCCESS;
00846     PRUint32 i = 0;
00847     PRBool foundIt;
00848     pkiObjectCollectionNode *node;
00849     if (instances) {
00850        for (; *instances; instances++, i++) {
00851            if (numInstances > 0 && i == numInstances) {
00852               break;
00853            }
00854            if (status == PR_SUCCESS) {
00855               node = add_object_instance(collection, *instances, &foundIt);
00856               if (node == NULL) {
00857                   /* add_object_instance freed the current instance */
00858                   /* free the remaining instances */
00859                   status = PR_FAILURE;
00860               }
00861            } else {
00862               nssCryptokiObject_Destroy(*instances);
00863            }
00864        }
00865     }
00866     return status;
00867 }
00868 
00869 static void
00870 nssPKIObjectCollection_RemoveNode (
00871    nssPKIObjectCollection *collection,
00872    pkiObjectCollectionNode *node
00873 )
00874 {
00875     PR_REMOVE_LINK(&node->link); 
00876     collection->size--;
00877 }
00878 
00879 static PRStatus
00880 nssPKIObjectCollection_GetObjects (
00881   nssPKIObjectCollection *collection,
00882   nssPKIObject **rvObjects,
00883   PRUint32 rvSize
00884 )
00885 {
00886     PRUint32 i = 0;
00887     PRCList *link = PR_NEXT_LINK(&collection->head);
00888     pkiObjectCollectionNode *node;
00889     int error=0;
00890     while ((i < rvSize) && (link != &collection->head)) {
00891        node = (pkiObjectCollectionNode *)link;
00892        if (!node->haveObject) {
00893            /* Convert the proto-object to an object */
00894            node->object = (*collection->createObject)(node->object);
00895            if (!node->object) {
00896               link = PR_NEXT_LINK(link);
00897               /*remove bogus object from list*/
00898               nssPKIObjectCollection_RemoveNode(collection,node);
00899               error++;
00900               continue;
00901            }
00902            node->haveObject = PR_TRUE;
00903        }
00904        rvObjects[i++] = nssPKIObject_AddRef(node->object);
00905        link = PR_NEXT_LINK(link);
00906     }
00907     if (!error && *rvObjects == NULL) {
00908        nss_SetError(NSS_ERROR_NOT_FOUND);
00909     }
00910     return PR_SUCCESS;
00911 }
00912 
00913 NSS_IMPLEMENT PRStatus
00914 nssPKIObjectCollection_Traverse (
00915   nssPKIObjectCollection *collection,
00916   nssPKIObjectCallback *callback
00917 )
00918 {
00919     PRStatus status;
00920     PRCList *link = PR_NEXT_LINK(&collection->head);
00921     pkiObjectCollectionNode *node;
00922     while (link != &collection->head) {
00923        node = (pkiObjectCollectionNode *)link;
00924        if (!node->haveObject) {
00925            node->object = (*collection->createObject)(node->object);
00926            if (!node->object) {
00927               link = PR_NEXT_LINK(link);
00928               /*remove bogus object from list*/
00929               nssPKIObjectCollection_RemoveNode(collection,node);
00930               continue;
00931            }
00932            node->haveObject = PR_TRUE;
00933        }
00934        switch (collection->objectType) {
00935        case pkiObjectType_Certificate: 
00936            status = (*callback->func.cert)((NSSCertificate *)node->object, 
00937                                            callback->arg);
00938            break;
00939        case pkiObjectType_CRL: 
00940            status = (*callback->func.crl)((NSSCRL *)node->object, 
00941                                           callback->arg);
00942            break;
00943        case pkiObjectType_PrivateKey: 
00944            status = (*callback->func.pvkey)((NSSPrivateKey *)node->object, 
00945                                             callback->arg);
00946            break;
00947        case pkiObjectType_PublicKey: 
00948            status = (*callback->func.pbkey)((NSSPublicKey *)node->object, 
00949                                             callback->arg);
00950            break;
00951        }
00952        link = PR_NEXT_LINK(link);
00953     }
00954     return PR_SUCCESS;
00955 }
00956 
00957 NSS_IMPLEMENT PRStatus
00958 nssPKIObjectCollection_AddInstanceAsObject (
00959   nssPKIObjectCollection *collection,
00960   nssCryptokiObject *instance
00961 )
00962 {
00963     pkiObjectCollectionNode *node;
00964     PRBool foundIt;
00965     node = add_object_instance(collection, instance, &foundIt);
00966     if (node == NULL) {
00967        return PR_FAILURE;
00968     }
00969     if (!node->haveObject) {
00970        node->object = (*collection->createObject)(node->object);
00971        if (!node->object) {
00972            /*remove bogus object from list*/
00973            nssPKIObjectCollection_RemoveNode(collection,node);
00974            return PR_FAILURE;
00975        }
00976        node->haveObject = PR_TRUE;
00977     } else if (!foundIt) {
00978        /* The instance was added to a pre-existing node.  This
00979         * function is *only* being used for certificates, and having
00980         * multiple instances of certs in 3.X requires updating the
00981         * CERTCertificate.
00982         * But only do it if it was a new instance!!!  If the same instance
00983         * is encountered, we set *foundIt to true.  Detect that here and
00984         * ignore it.
00985         */
00986        STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
00987     }
00988     return PR_SUCCESS;
00989 }
00990 
00991 /*
00992  * Certificate collections
00993  */
00994 
00995 static void
00996 cert_destroyObject(nssPKIObject *o)
00997 {
00998     NSSCertificate *c = (NSSCertificate *)o;
00999     if (c->decoding) {
01000        CERTCertificate *cc = STAN_GetCERTCertificate(c);
01001        if (cc) {
01002            CERT_DestroyCertificate(cc);
01003            return;
01004        } /* else destroy it as NSSCertificate below */
01005     }
01006     nssCertificate_Destroy(c);
01007 }
01008 
01009 static PRStatus
01010 cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
01011 {
01012     NSSCertificate *c = (NSSCertificate *)o;
01013     /* The builtins are still returning decoded serial numbers.  Until
01014      * this compatibility issue is resolved, use the full DER of the
01015      * cert to uniquely identify it.
01016      */
01017     NSSDER *derCert;
01018     derCert = nssCertificate_GetEncoding(c);
01019     uid[0].data = NULL; uid[0].size = 0;
01020     uid[1].data = NULL; uid[1].size = 0;
01021     if (derCert != NULL) {
01022        uid[0] = *derCert;
01023     }
01024     return PR_SUCCESS;
01025 }
01026 
01027 static PRStatus
01028 cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
01029                         NSSArena *arena)
01030 {
01031     /* The builtins are still returning decoded serial numbers.  Until
01032      * this compatibility issue is resolved, use the full DER of the
01033      * cert to uniquely identify it.
01034      */
01035     uid[1].data = NULL; uid[1].size = 0;
01036     return nssCryptokiCertificate_GetAttributes(instance,
01037                                                 NULL,  /* XXX sessionOpt */
01038                                                 arena, /* arena    */
01039                                                 NULL,  /* type     */
01040                                                 NULL,  /* id       */
01041                                                 &uid[0], /* encoding */
01042                                                 NULL,  /* issuer   */
01043                                                 NULL,  /* serial   */
01044                                                 NULL);  /* subject  */
01045 }
01046 
01047 static nssPKIObject *
01048 cert_createObject(nssPKIObject *o)
01049 {
01050     NSSCertificate *cert;
01051     cert = nssCertificate_Create(o);
01052 /*    if (STAN_GetCERTCertificate(cert) == NULL) {
01053        nssCertificate_Destroy(cert);
01054        return (nssPKIObject *)NULL;
01055     } */
01056     /* In 3.4, have to maintain uniqueness of cert pointers by caching all
01057      * certs.  Cache the cert here, before returning.  If it is already
01058      * cached, take the cached entry.
01059      */
01060     {
01061        NSSTrustDomain *td = o->trustDomain;
01062        nssTrustDomain_AddCertsToCache(td, &cert, 1);
01063     }
01064     return (nssPKIObject *)cert;
01065 }
01066 
01067 NSS_IMPLEMENT nssPKIObjectCollection *
01068 nssCertificateCollection_Create (
01069   NSSTrustDomain *td,
01070   NSSCertificate **certsOpt
01071 )
01072 {
01073     PRStatus status;
01074     nssPKIObjectCollection *collection;
01075     collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
01076     collection->objectType = pkiObjectType_Certificate;
01077     collection->destroyObject = cert_destroyObject;
01078     collection->getUIDFromObject = cert_getUIDFromObject;
01079     collection->getUIDFromInstance = cert_getUIDFromInstance;
01080     collection->createObject = cert_createObject;
01081     if (certsOpt) {
01082        for (; *certsOpt; certsOpt++) {
01083            nssPKIObject *object = (nssPKIObject *)(*certsOpt);
01084            status = nssPKIObjectCollection_AddObject(collection, object);
01085        }
01086     }
01087     return collection;
01088 }
01089 
01090 NSS_IMPLEMENT NSSCertificate **
01091 nssPKIObjectCollection_GetCertificates (
01092   nssPKIObjectCollection *collection,
01093   NSSCertificate **rvOpt,
01094   PRUint32 maximumOpt,
01095   NSSArena *arenaOpt
01096 )
01097 {
01098     PRStatus status;
01099     PRUint32 rvSize;
01100     PRBool allocated = PR_FALSE;
01101     if (collection->size == 0) {
01102        return (NSSCertificate **)NULL;
01103     }
01104     if (maximumOpt == 0) {
01105        rvSize = collection->size;
01106     } else {
01107        rvSize = PR_MIN(collection->size, maximumOpt);
01108     }
01109     if (!rvOpt) {
01110        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
01111        if (!rvOpt) {
01112            return (NSSCertificate **)NULL;
01113        }
01114        allocated = PR_TRUE;
01115     }
01116     status = nssPKIObjectCollection_GetObjects(collection, 
01117                                                (nssPKIObject **)rvOpt, 
01118                                                rvSize);
01119     if (status != PR_SUCCESS) {
01120        if (allocated) {
01121            nss_ZFreeIf(rvOpt);
01122        }
01123        return (NSSCertificate **)NULL;
01124     }
01125     return rvOpt;
01126 }
01127 
01128 /*
01129  * CRL/KRL collections
01130  */
01131 
01132 static void
01133 crl_destroyObject(nssPKIObject *o)
01134 {
01135     NSSCRL *crl = (NSSCRL *)o;
01136     nssCRL_Destroy(crl);
01137 }
01138 
01139 static PRStatus
01140 crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
01141 {
01142     NSSCRL *crl = (NSSCRL *)o;
01143     NSSDER *encoding;
01144     encoding = nssCRL_GetEncoding(crl);
01145     uid[0] = *encoding;
01146     uid[1].data = NULL; uid[1].size = 0;
01147     return PR_SUCCESS;
01148 }
01149 
01150 static PRStatus
01151 crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 
01152                        NSSArena *arena)
01153 {
01154     return nssCryptokiCRL_GetAttributes(instance,
01155                                         NULL,    /* XXX sessionOpt */
01156                                         arena,   /* arena    */
01157                                         &uid[0], /* encoding */
01158                                         NULL,    /* subject  */
01159                                         NULL,    /* class    */
01160                                         NULL,    /* url      */
01161                                         NULL);   /* isKRL    */
01162 }
01163 
01164 static nssPKIObject *
01165 crl_createObject(nssPKIObject *o)
01166 {
01167     return (nssPKIObject *)nssCRL_Create(o);
01168 }
01169 
01170 NSS_IMPLEMENT nssPKIObjectCollection *
01171 nssCRLCollection_Create (
01172   NSSTrustDomain *td,
01173   NSSCRL **crlsOpt
01174 )
01175 {
01176     PRStatus status;
01177     nssPKIObjectCollection *collection;
01178     collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
01179     collection->objectType = pkiObjectType_CRL;
01180     collection->destroyObject = crl_destroyObject;
01181     collection->getUIDFromObject = crl_getUIDFromObject;
01182     collection->getUIDFromInstance = crl_getUIDFromInstance;
01183     collection->createObject = crl_createObject;
01184     if (crlsOpt) {
01185        for (; *crlsOpt; crlsOpt++) {
01186            nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
01187            status = nssPKIObjectCollection_AddObject(collection, object);
01188        }
01189     }
01190     return collection;
01191 }
01192 
01193 NSS_IMPLEMENT NSSCRL **
01194 nssPKIObjectCollection_GetCRLs (
01195   nssPKIObjectCollection *collection,
01196   NSSCRL **rvOpt,
01197   PRUint32 maximumOpt,
01198   NSSArena *arenaOpt
01199 )
01200 {
01201     PRStatus status;
01202     PRUint32 rvSize;
01203     PRBool allocated = PR_FALSE;
01204     if (collection->size == 0) {
01205        return (NSSCRL **)NULL;
01206     }
01207     if (maximumOpt == 0) {
01208        rvSize = collection->size;
01209     } else {
01210        rvSize = PR_MIN(collection->size, maximumOpt);
01211     }
01212     if (!rvOpt) {
01213        rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
01214        if (!rvOpt) {
01215            return (NSSCRL **)NULL;
01216        }
01217        allocated = PR_TRUE;
01218     }
01219     status = nssPKIObjectCollection_GetObjects(collection, 
01220                                                (nssPKIObject **)rvOpt, 
01221                                                rvSize);
01222     if (status != PR_SUCCESS) {
01223        if (allocated) {
01224            nss_ZFreeIf(rvOpt);
01225        }
01226        return (NSSCRL **)NULL;
01227     }
01228     return rvOpt;
01229 }
01230 
01231 /* how bad would it be to have a static now sitting around, updated whenever
01232  * this was called?  would avoid repeated allocs...
01233  */
01234 NSS_IMPLEMENT NSSTime *
01235 NSSTime_Now (
01236   NSSTime *timeOpt
01237 )
01238 {
01239     return NSSTime_SetPRTime(timeOpt, PR_Now());
01240 }
01241 
01242 NSS_IMPLEMENT NSSTime *
01243 NSSTime_SetPRTime (
01244   NSSTime *timeOpt,
01245   PRTime prTime
01246 )
01247 {
01248     NSSTime *rvTime;
01249     rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
01250     rvTime->prTime = prTime;
01251     return rvTime;
01252 }
01253 
01254 NSS_IMPLEMENT PRTime
01255 NSSTime_GetPRTime (
01256   NSSTime *time
01257 )
01258 {
01259   return time->prTime;
01260 }
01261