/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DEV_H #include "dev.h" #endif /* DEV_H */ #ifndef PKIM_H #include "pkim.h" #endif /* PKIM_H */ #include "pki3hack.h" extern const NSSError NSS_ERROR_NOT_FOUND; NSS_IMPLEMENT void nssPKIObject_Lock(nssPKIObject *object) { switch (object->lockType) { case nssPKIMonitor: PZ_EnterMonitor(object->sync.mlock); break; case nssPKILock: PZ_Lock(object->sync.lock); break; default: PORT_Assert(0); } } NSS_IMPLEMENT void nssPKIObject_Unlock(nssPKIObject *object) { switch (object->lockType) { case nssPKIMonitor: PZ_ExitMonitor(object->sync.mlock); break; case nssPKILock: PZ_Unlock(object->sync.lock); break; default: PORT_Assert(0); } } NSS_IMPLEMENT PRStatus nssPKIObject_NewLock(nssPKIObject *object, nssPKILockType lockType) { object->lockType = lockType; switch (lockType) { case nssPKIMonitor: object->sync.mlock = PZ_NewMonitor(nssILockSSL); return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE); case nssPKILock: object->sync.lock = PZ_NewLock(nssILockSSL); return (object->sync.lock ? PR_SUCCESS : PR_FAILURE); default: PORT_Assert(0); return PR_FAILURE; } } NSS_IMPLEMENT void nssPKIObject_DestroyLock(nssPKIObject *object) { switch (object->lockType) { case nssPKIMonitor: PZ_DestroyMonitor(object->sync.mlock); object->sync.mlock = NULL; break; case nssPKILock: PZ_DestroyLock(object->sync.lock); object->sync.lock = NULL; break; default: PORT_Assert(0); } } NSS_IMPLEMENT nssPKIObject * nssPKIObject_Create( NSSArena *arenaOpt, nssCryptokiObject *instanceOpt, NSSTrustDomain *td, NSSCryptoContext *cc, nssPKILockType lockType) { NSSArena *arena; nssArenaMark *mark = NULL; nssPKIObject *object; if (arenaOpt) { arena = arenaOpt; mark = nssArena_Mark(arena); } else { arena = nssArena_Create(); if (!arena) { return (nssPKIObject *)NULL; } } object = nss_ZNEW(arena, nssPKIObject); if (!object) { goto loser; } object->arena = arena; object->trustDomain = td; /* XXX */ object->cryptoContext = cc; if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) { goto loser; } if (instanceOpt) { if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) { goto loser; } } PR_ATOMIC_INCREMENT(&object->refCount); if (mark) { nssArena_Unmark(arena, mark); } return object; loser: if (mark) { nssArena_Release(arena, mark); } else { nssArena_Destroy(arena); } return (nssPKIObject *)NULL; } NSS_IMPLEMENT PRBool nssPKIObject_Destroy( nssPKIObject *object) { PRUint32 i; PR_ASSERT(object->refCount > 0); if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) { for (i = 0; i < object->numInstances; i++) { nssCryptokiObject_Destroy(object->instances[i]); } nssPKIObject_DestroyLock(object); nssArena_Destroy(object->arena); return PR_TRUE; } return PR_FALSE; } NSS_IMPLEMENT nssPKIObject * nssPKIObject_AddRef( nssPKIObject *object) { PR_ATOMIC_INCREMENT(&object->refCount); return object; } NSS_IMPLEMENT PRStatus nssPKIObject_AddInstance( nssPKIObject *object, nssCryptokiObject *instance) { nssCryptokiObject **newInstances = NULL; nssPKIObject_Lock(object); if (object->numInstances == 0) { newInstances = nss_ZNEWARRAY(object->arena, nssCryptokiObject *, object->numInstances + 1); } else { PRBool found = PR_FALSE; PRUint32 i; for (i = 0; i < object->numInstances; i++) { if (nssCryptokiObject_Equal(object->instances[i], instance)) { found = PR_TRUE; break; } } if (found) { /* The new instance is identical to one in the array, except * perhaps that the label may be different. So replace * the label in the array instance with the label from the * new instance, and discard the new instance. */ nss_ZFreeIf(object->instances[i]->label); object->instances[i]->label = instance->label; nssPKIObject_Unlock(object); instance->label = NULL; nssCryptokiObject_Destroy(instance); return PR_SUCCESS; } newInstances = nss_ZREALLOCARRAY(object->instances, nssCryptokiObject *, object->numInstances + 1); } if (newInstances) { object->instances = newInstances; newInstances[object->numInstances++] = instance; } nssPKIObject_Unlock(object); return (newInstances ? PR_SUCCESS : PR_FAILURE); } NSS_IMPLEMENT PRBool nssPKIObject_HasInstance( nssPKIObject *object, nssCryptokiObject *instance) { PRUint32 i; PRBool hasIt = PR_FALSE; ; nssPKIObject_Lock(object); for (i = 0; i < object->numInstances; i++) { if (nssCryptokiObject_Equal(object->instances[i], instance)) { hasIt = PR_TRUE; break; } } nssPKIObject_Unlock(object); return hasIt; } NSS_IMPLEMENT PRStatus nssPKIObject_RemoveInstanceForToken( nssPKIObject *object, NSSToken *token) { PRUint32 i; nssCryptokiObject *instanceToRemove = NULL; nssPKIObject_Lock(object); if (object->numInstances == 0) { nssPKIObject_Unlock(object); return PR_SUCCESS; } for (i = 0; i < object->numInstances; i++) { if (object->instances[i]->token == token) { instanceToRemove = object->instances[i]; object->instances[i] = object->instances[object->numInstances - 1]; object->instances[object->numInstances - 1] = NULL; break; } } if (--object->numInstances > 0) { nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances, nssCryptokiObject *, object->numInstances); if (instances) { object->instances = instances; } } else { nss_ZFreeIf(object->instances); } nssCryptokiObject_Destroy(instanceToRemove); nssPKIObject_Unlock(object); return PR_SUCCESS; } /* this needs more thought on what will happen when there are multiple * instances */ NSS_IMPLEMENT PRStatus nssPKIObject_DeleteStoredObject( nssPKIObject *object, NSSCallback *uhh, PRBool isFriendly) { PRUint32 i, numNotDestroyed; PRStatus status = PR_SUCCESS; numNotDestroyed = 0; nssPKIObject_Lock(object); for (i = 0; i < object->numInstances; i++) { nssCryptokiObject *instance = object->instances[i]; status = nssToken_DeleteStoredObject(instance); object->instances[i] = NULL; if (status == PR_SUCCESS) { nssCryptokiObject_Destroy(instance); } else { object->instances[numNotDestroyed++] = instance; } } if (numNotDestroyed == 0) { nss_ZFreeIf(object->instances); object->numInstances = 0; } else { object->numInstances = numNotDestroyed; } nssPKIObject_Unlock(object); return status; } NSS_IMPLEMENT NSSToken ** nssPKIObject_GetTokens( nssPKIObject *object, PRStatus *statusOpt) { NSSToken **tokens = NULL; nssPKIObject_Lock(object); if (object->numInstances > 0) { tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1); if (tokens) { PRUint32 i; for (i = 0; i < object->numInstances; i++) { tokens[i] = nssToken_AddRef(object->instances[i]->token); } } } nssPKIObject_Unlock(object); if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */ return tokens; } NSS_IMPLEMENT NSSUTF8 * nssPKIObject_GetNicknameForToken( nssPKIObject *object, NSSToken *tokenOpt) { PRUint32 i; NSSUTF8 *nickname = NULL; nssPKIObject_Lock(object); for (i = 0; i < object->numInstances; i++) { if ((!tokenOpt && object->instances[i]->label) || (object->instances[i]->token == tokenOpt)) { /* Must copy, see bug 745548 */ nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL); break; } } nssPKIObject_Unlock(object); return nickname; } NSS_IMPLEMENT nssCryptokiObject ** nssPKIObject_GetInstances( nssPKIObject *object) { nssCryptokiObject **instances = NULL; PRUint32 i; if (object->numInstances == 0) { return (nssCryptokiObject **)NULL; } nssPKIObject_Lock(object); instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, object->numInstances + 1); if (instances) { for (i = 0; i < object->numInstances; i++) { instances[i] = nssCryptokiObject_Clone(object->instances[i]); } } nssPKIObject_Unlock(object); return instances; } NSS_IMPLEMENT void nssCertificateArray_Destroy( NSSCertificate **certs) { if (certs) { NSSCertificate **certp; for (certp = certs; *certp; certp++) { if ((*certp)->decoding) { CERTCertificate *cc = STAN_GetCERTCertificate(*certp); if (cc) { CERT_DestroyCertificate(cc); } continue; } nssCertificate_Destroy(*certp); } nss_ZFreeIf(certs); } } NSS_IMPLEMENT void NSSCertificateArray_Destroy( NSSCertificate **certs) { nssCertificateArray_Destroy(certs); } NSS_IMPLEMENT NSSCertificate ** nssCertificateArray_Join( NSSCertificate **certs1, NSSCertificate **certs2) { if (certs1 && certs2) { NSSCertificate **certs, **cp; PRUint32 count = 0; PRUint32 count1 = 0; cp = certs1; while (*cp++) count1++; count = count1; cp = certs2; while (*cp++) count++; certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1); if (!certs) { nss_ZFreeIf(certs1); nss_ZFreeIf(certs2); return (NSSCertificate **)NULL; } for (cp = certs2; *cp; cp++, count1++) { certs[count1] = *cp; } nss_ZFreeIf(certs2); return certs; } else if (certs1) { return certs1; } else { return certs2; } } NSS_IMPLEMENT NSSCertificate * nssCertificateArray_FindBestCertificate( NSSCertificate **certs, NSSTime *timeOpt, const NSSUsage *usage, NSSPolicies *policiesOpt) { NSSCertificate *bestCert = NULL; nssDecodedCert *bestdc = NULL; NSSTime *time, sTime; PRBool bestCertMatches = PR_FALSE; PRBool thisCertMatches; PRBool bestCertIsValidAtTime = PR_FALSE; PRBool bestCertIsTrusted = PR_FALSE; if (timeOpt) { time = timeOpt; } else { NSSTime_Now(&sTime); time = &sTime; } if (!certs) { return (NSSCertificate *)NULL; } for (; *certs; certs++) { nssDecodedCert *dc; NSSCertificate *c = *certs; dc = nssCertificate_GetDecoding(c); if (!dc) continue; thisCertMatches = dc->matchUsage(dc, usage); if (!bestCert) { /* always take the first cert, but remember whether or not * the usage matched */ bestCert = nssCertificate_AddRef(c); bestCertMatches = thisCertMatches; bestdc = dc; continue; } else { if (bestCertMatches && !thisCertMatches) { /* if already have a cert for this usage, and if this cert * doesn't have the correct usage, continue */ continue; } else if (!bestCertMatches && thisCertMatches) { /* this one does match usage, replace the other */ nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); bestCertMatches = thisCertMatches; bestdc = dc; continue; } /* this cert match as well as any cert we've found so far, * defer to time/policies * */ } /* time */ if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) { /* The current best cert is valid at time */ bestCertIsValidAtTime = PR_TRUE; if (!dc->isValidAtTime(dc, time)) { /* If the new cert isn't valid at time, it's not better */ continue; } } else { /* The current best cert is not valid at time */ if (dc->isValidAtTime(dc, time)) { /* If the new cert is valid at time, it's better */ nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); bestdc = dc; bestCertIsValidAtTime = PR_TRUE; continue; } } /* Either they are both valid at time, or neither valid. * If only one is trusted for this usage, take it. */ if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) { bestCertIsTrusted = PR_TRUE; if (!dc->isTrustedForUsage(dc, usage)) { continue; } } else { /* The current best cert is not trusted */ if (dc->isTrustedForUsage(dc, usage)) { /* If the new cert is trusted, it's better */ nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); bestdc = dc; bestCertIsTrusted = PR_TRUE; continue; } } /* Otherwise, take the newer one. */ if (!bestdc->isNewerThan(bestdc, dc)) { nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); bestdc = dc; continue; } /* policies */ /* XXX later -- defer to policies */ } return bestCert; } NSS_IMPLEMENT PRStatus nssCertificateArray_Traverse( NSSCertificate **certs, PRStatus (*callback)(NSSCertificate *c, void *arg), void *arg) { PRStatus status = PR_SUCCESS; if (certs) { NSSCertificate **certp; for (certp = certs; *certp; certp++) { status = (*callback)(*certp, arg); if (status != PR_SUCCESS) { break; } } } return status; } NSS_IMPLEMENT void nssCRLArray_Destroy( NSSCRL **crls) { if (crls) { NSSCRL **crlp; for (crlp = crls; *crlp; crlp++) { nssCRL_Destroy(*crlp); } nss_ZFreeIf(crls); } } /* * Object collections */ typedef enum { pkiObjectType_Certificate = 0, pkiObjectType_CRL = 1, pkiObjectType_PrivateKey = 2, pkiObjectType_PublicKey = 3 } pkiObjectType; /* Each object is defined by a set of items that uniquely identify it. * Here are the uid sets: * * NSSCertificate ==> { issuer, serial } * NSSPrivateKey * (RSA) ==> { modulus, public exponent } * */ #define MAX_ITEMS_FOR_UID 2 /* pkiObjectCollectionNode * * A node in the collection is the set of unique identifiers for a single * object, along with either the actual object or a proto-object. */ typedef struct { PRCList link; PRBool haveObject; nssPKIObject *object; NSSItem uid[MAX_ITEMS_FOR_UID]; } pkiObjectCollectionNode; /* nssPKIObjectCollection * * The collection is the set of all objects, plus the interfaces needed * to manage the objects. * */ struct nssPKIObjectCollectionStr { NSSArena *arena; NSSTrustDomain *td; NSSCryptoContext *cc; PRCList head; /* list of pkiObjectCollectionNode's */ PRUint32 size; pkiObjectType objectType; void (*destroyObject)(nssPKIObject *o); PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid); PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, NSSArena *arena); nssPKIObject *(*createObject)(nssPKIObject *o); nssPKILockType lockType; /* type of lock to use for new proto-objects */ }; static nssPKIObjectCollection * nssPKIObjectCollection_Create( NSSTrustDomain *td, NSSCryptoContext *ccOpt, nssPKILockType lockType) { NSSArena *arena; nssPKIObjectCollection *rvCollection = NULL; arena = nssArena_Create(); if (!arena) { return (nssPKIObjectCollection *)NULL; } rvCollection = nss_ZNEW(arena, nssPKIObjectCollection); if (!rvCollection) { goto loser; } PR_INIT_CLIST(&rvCollection->head); rvCollection->arena = arena; rvCollection->td = td; /* XXX */ rvCollection->cc = ccOpt; rvCollection->lockType = lockType; return rvCollection; loser: nssArena_Destroy(arena); return (nssPKIObjectCollection *)NULL; } NSS_IMPLEMENT void nssPKIObjectCollection_Destroy( nssPKIObjectCollection *collection) { if (collection) { PRCList *link; pkiObjectCollectionNode *node; /* first destroy any objects in the collection */ link = PR_NEXT_LINK(&collection->head); while (link != &collection->head) { node = (pkiObjectCollectionNode *)link; if (node->haveObject) { (*collection->destroyObject)(node->object); } else { nssPKIObject_Destroy(node->object); } link = PR_NEXT_LINK(link); } /* then destroy it */ nssArena_Destroy(collection->arena); } } NSS_IMPLEMENT PRUint32 nssPKIObjectCollection_Count( nssPKIObjectCollection *collection) { return collection->size; } NSS_IMPLEMENT PRStatus nssPKIObjectCollection_AddObject( nssPKIObjectCollection *collection, nssPKIObject *object) { pkiObjectCollectionNode *node; node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); if (!node) { return PR_FAILURE; } node->haveObject = PR_TRUE; node->object = nssPKIObject_AddRef(object); (*collection->getUIDFromObject)(object, node->uid); PR_INIT_CLIST(&node->link); PR_INSERT_BEFORE(&node->link, &collection->head); collection->size++; return PR_SUCCESS; } static pkiObjectCollectionNode * find_instance_in_collection( nssPKIObjectCollection *collection, nssCryptokiObject *instance) { PRCList *link; pkiObjectCollectionNode *node; link = PR_NEXT_LINK(&collection->head); while (link != &collection->head) { node = (pkiObjectCollectionNode *)link; if (nssPKIObject_HasInstance(node->object, instance)) { return node; } link = PR_NEXT_LINK(link); } return (pkiObjectCollectionNode *)NULL; } static pkiObjectCollectionNode * find_object_in_collection( nssPKIObjectCollection *collection, NSSItem *uid) { PRUint32 i; PRStatus status; PRCList *link; pkiObjectCollectionNode *node; link = PR_NEXT_LINK(&collection->head); while (link != &collection->head) { node = (pkiObjectCollectionNode *)link; for (i = 0; i < MAX_ITEMS_FOR_UID; i++) { if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) { break; } } if (i == MAX_ITEMS_FOR_UID) { return node; } link = PR_NEXT_LINK(link); } return (pkiObjectCollectionNode *)NULL; } static pkiObjectCollectionNode * add_object_instance( nssPKIObjectCollection *collection, nssCryptokiObject *instance, PRBool *foundIt) { PRUint32 i; PRStatus status; pkiObjectCollectionNode *node; nssArenaMark *mark = NULL; NSSItem uid[MAX_ITEMS_FOR_UID]; nsslibc_memset(uid, 0, sizeof uid); /* The list is traversed twice, first (here) looking to match the * { token, handle } tuple, and if that is not found, below a search * for unique identifier is done. Here, a match means this exact object * instance is already in the collection, and we have nothing to do. */ *foundIt = PR_FALSE; node = find_instance_in_collection(collection, instance); if (node) { /* The collection is assumed to take over the instance. Since we * are not using it, it must be destroyed. */ nssCryptokiObject_Destroy(instance); *foundIt = PR_TRUE; return node; } mark = nssArena_Mark(collection->arena); if (!mark) { goto loser; } status = (*collection->getUIDFromInstance)(instance, uid, collection->arena); if (status != PR_SUCCESS) { goto loser; } /* Search for unique identifier. A match here means the object exists * in the collection, but does not have this instance, so the instance * needs to be added. */ node = find_object_in_collection(collection, uid); if (node) { /* This is an object with multiple instances */ status = nssPKIObject_AddInstance(node->object, instance); } else { /* This is a completely new object. Create a node for it. */ node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); if (!node) { goto loser; } node->object = nssPKIObject_Create(NULL, instance, collection->td, collection->cc, collection->lockType); if (!node->object) { goto loser; } for (i = 0; i < MAX_ITEMS_FOR_UID; i++) { node->uid[i] = uid[i]; } node->haveObject = PR_FALSE; PR_INIT_CLIST(&node->link); PR_INSERT_BEFORE(&node->link, &collection->head); collection->size++; status = PR_SUCCESS; } nssArena_Unmark(collection->arena, mark); return node; loser: if (mark) { nssArena_Release(collection->arena, mark); } nssCryptokiObject_Destroy(instance); return (pkiObjectCollectionNode *)NULL; } NSS_IMPLEMENT PRStatus nssPKIObjectCollection_AddInstances( nssPKIObjectCollection *collection, nssCryptokiObject **instances, PRUint32 numInstances) { PRStatus status = PR_SUCCESS; PRUint32 i = 0; PRBool foundIt; pkiObjectCollectionNode *node; if (instances) { while ((!numInstances || i < numInstances) && *instances) { if (status == PR_SUCCESS) { node = add_object_instance(collection, *instances, &foundIt); if (node == NULL) { /* add_object_instance freed the current instance */ /* free the remaining instances */ status = PR_FAILURE; } } else { nssCryptokiObject_Destroy(*instances); } instances++; i++; } } return status; } static void nssPKIObjectCollection_RemoveNode( nssPKIObjectCollection *collection, pkiObjectCollectionNode *node) { PR_REMOVE_LINK(&node->link); collection->size--; } static PRStatus nssPKIObjectCollection_GetObjects( nssPKIObjectCollection *collection, nssPKIObject **rvObjects, PRUint32 rvSize) { PRUint32 i = 0; PRCList *link = PR_NEXT_LINK(&collection->head); pkiObjectCollectionNode *node; int error = 0; while ((i < rvSize) && (link != &collection->head)) { node = (pkiObjectCollectionNode *)link; if (!node->haveObject) { /* Convert the proto-object to an object */ node->object = (*collection->createObject)(node->object); if (!node->object) { link = PR_NEXT_LINK(link); /*remove bogus object from list*/ nssPKIObjectCollection_RemoveNode(collection, node); error++; continue; } node->haveObject = PR_TRUE; } rvObjects[i++] = nssPKIObject_AddRef(node->object); link = PR_NEXT_LINK(link); } if (!error && *rvObjects == NULL) { nss_SetError(NSS_ERROR_NOT_FOUND); } return PR_SUCCESS; } NSS_IMPLEMENT PRStatus nssPKIObjectCollection_Traverse( nssPKIObjectCollection *collection, nssPKIObjectCallback *callback) { PRCList *link = PR_NEXT_LINK(&collection->head); pkiObjectCollectionNode *node; while (link != &collection->head) { node = (pkiObjectCollectionNode *)link; if (!node->haveObject) { node->object = (*collection->createObject)(node->object); if (!node->object) { link = PR_NEXT_LINK(link); /*remove bogus object from list*/ nssPKIObjectCollection_RemoveNode(collection, node); continue; } node->haveObject = PR_TRUE; } switch (collection->objectType) { case pkiObjectType_Certificate: (void)(*callback->func.cert)((NSSCertificate *)node->object, callback->arg); break; case pkiObjectType_CRL: (void)(*callback->func.crl)((NSSCRL *)node->object, callback->arg); break; case pkiObjectType_PrivateKey: (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object, callback->arg); break; case pkiObjectType_PublicKey: (void)(*callback->func.pbkey)((NSSPublicKey *)node->object, callback->arg); break; } link = PR_NEXT_LINK(link); } return PR_SUCCESS; } NSS_IMPLEMENT PRStatus nssPKIObjectCollection_AddInstanceAsObject( nssPKIObjectCollection *collection, nssCryptokiObject *instance) { pkiObjectCollectionNode *node; PRBool foundIt; node = add_object_instance(collection, instance, &foundIt); if (node == NULL) { return PR_FAILURE; } if (!node->haveObject) { nssPKIObject *original = node->object; node->object = (*collection->createObject)(node->object); if (!node->object) { /*remove bogus object from list*/ nssPKIObject_Destroy(original); nssPKIObjectCollection_RemoveNode(collection, node); return PR_FAILURE; } node->haveObject = PR_TRUE; } else if (!foundIt) { /* The instance was added to a pre-existing node. This * function is *only* being used for certificates, and having * multiple instances of certs in 3.X requires updating the * CERTCertificate. * But only do it if it was a new instance!!! If the same instance * is encountered, we set *foundIt to true. Detect that here and * ignore it. */ STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object); } return PR_SUCCESS; } /* * Certificate collections */ static void cert_destroyObject(nssPKIObject *o) { NSSCertificate *c = (NSSCertificate *)o; if (c->decoding) { CERTCertificate *cc = STAN_GetCERTCertificate(c); if (cc) { CERT_DestroyCertificate(cc); return; } /* else destroy it as NSSCertificate below */ } nssCertificate_Destroy(c); } static PRStatus cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid) { NSSCertificate *c = (NSSCertificate *)o; /* The builtins are still returning decoded serial numbers. Until * this compatibility issue is resolved, use the full DER of the * cert to uniquely identify it. */ NSSDER *derCert; derCert = nssCertificate_GetEncoding(c); uid[0].data = NULL; uid[0].size = 0; uid[1].data = NULL; uid[1].size = 0; if (derCert != NULL) { uid[0] = *derCert; } return PR_SUCCESS; } static PRStatus cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, NSSArena *arena) { /* The builtins are still returning decoded serial numbers. Until * this compatibility issue is resolved, use the full DER of the * cert to uniquely identify it. */ uid[1].data = NULL; uid[1].size = 0; return nssCryptokiCertificate_GetAttributes(instance, NULL, /* XXX sessionOpt */ arena, /* arena */ NULL, /* type */ NULL, /* id */ &uid[0], /* encoding */ NULL, /* issuer */ NULL, /* serial */ NULL); /* subject */ } static nssPKIObject * cert_createObject(nssPKIObject *o) { NSSCertificate *cert; cert = nssCertificate_Create(o); /* if (STAN_GetCERTCertificate(cert) == NULL) { nssCertificate_Destroy(cert); return (nssPKIObject *)NULL; } */ /* In 3.4, have to maintain uniqueness of cert pointers by caching all * certs. Cache the cert here, before returning. If it is already * cached, take the cached entry. */ { NSSTrustDomain *td = o->trustDomain; nssTrustDomain_AddCertsToCache(td, &cert, 1); } return (nssPKIObject *)cert; } NSS_IMPLEMENT nssPKIObjectCollection * nssCertificateCollection_Create( NSSTrustDomain *td, NSSCertificate **certsOpt) { nssPKIObjectCollection *collection; collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor); if (!collection) { return NULL; } collection->objectType = pkiObjectType_Certificate; collection->destroyObject = cert_destroyObject; collection->getUIDFromObject = cert_getUIDFromObject; collection->getUIDFromInstance = cert_getUIDFromInstance; collection->createObject = cert_createObject; if (certsOpt) { for (; *certsOpt; certsOpt++) { nssPKIObject *object = (nssPKIObject *)(*certsOpt); (void)nssPKIObjectCollection_AddObject(collection, object); } } return collection; } NSS_IMPLEMENT NSSCertificate ** nssPKIObjectCollection_GetCertificates( nssPKIObjectCollection *collection, NSSCertificate **rvOpt, PRUint32 maximumOpt, NSSArena *arenaOpt) { PRStatus status; PRUint32 rvSize; PRBool allocated = PR_FALSE; if (collection->size == 0) { return (NSSCertificate **)NULL; } if (maximumOpt == 0) { rvSize = collection->size; } else { rvSize = PR_MIN(collection->size, maximumOpt); } if (!rvOpt) { rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1); if (!rvOpt) { return (NSSCertificate **)NULL; } allocated = PR_TRUE; } status = nssPKIObjectCollection_GetObjects(collection, (nssPKIObject **)rvOpt, rvSize); if (status != PR_SUCCESS) { if (allocated) { nss_ZFreeIf(rvOpt); } return (NSSCertificate **)NULL; } return rvOpt; } /* * CRL/KRL collections */ static void crl_destroyObject(nssPKIObject *o) { NSSCRL *crl = (NSSCRL *)o; nssCRL_Destroy(crl); } static PRStatus crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid) { NSSCRL *crl = (NSSCRL *)o; NSSDER *encoding; encoding = nssCRL_GetEncoding(crl); if (!encoding) { nss_SetError(NSS_ERROR_INVALID_ARGUMENT); return PR_FALSE; } uid[0] = *encoding; uid[1].data = NULL; uid[1].size = 0; return PR_SUCCESS; } static PRStatus crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, NSSArena *arena) { return nssCryptokiCRL_GetAttributes(instance, NULL, /* XXX sessionOpt */ arena, /* arena */ &uid[0], /* encoding */ NULL, /* subject */ NULL, /* class */ NULL, /* url */ NULL); /* isKRL */ } static nssPKIObject * crl_createObject(nssPKIObject *o) { return (nssPKIObject *)nssCRL_Create(o); } NSS_IMPLEMENT nssPKIObjectCollection * nssCRLCollection_Create( NSSTrustDomain *td, NSSCRL **crlsOpt) { nssPKIObjectCollection *collection; collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock); if (!collection) { return NULL; } collection->objectType = pkiObjectType_CRL; collection->destroyObject = crl_destroyObject; collection->getUIDFromObject = crl_getUIDFromObject; collection->getUIDFromInstance = crl_getUIDFromInstance; collection->createObject = crl_createObject; if (crlsOpt) { for (; *crlsOpt; crlsOpt++) { nssPKIObject *object = (nssPKIObject *)(*crlsOpt); (void)nssPKIObjectCollection_AddObject(collection, object); } } return collection; } NSS_IMPLEMENT NSSCRL ** nssPKIObjectCollection_GetCRLs( nssPKIObjectCollection *collection, NSSCRL **rvOpt, PRUint32 maximumOpt, NSSArena *arenaOpt) { PRStatus status; PRUint32 rvSize; PRBool allocated = PR_FALSE; if (collection->size == 0) { return (NSSCRL **)NULL; } if (maximumOpt == 0) { rvSize = collection->size; } else { rvSize = PR_MIN(collection->size, maximumOpt); } if (!rvOpt) { rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1); if (!rvOpt) { return (NSSCRL **)NULL; } allocated = PR_TRUE; } status = nssPKIObjectCollection_GetObjects(collection, (nssPKIObject **)rvOpt, rvSize); if (status != PR_SUCCESS) { if (allocated) { nss_ZFreeIf(rvOpt); } return (NSSCRL **)NULL; } return rvOpt; } /* how bad would it be to have a static now sitting around, updated whenever * this was called? would avoid repeated allocs... */ NSS_IMPLEMENT NSSTime * NSSTime_Now(NSSTime *timeOpt) { return NSSTime_SetPRTime(timeOpt, PR_Now()); } NSS_IMPLEMENT NSSTime * NSSTime_SetPRTime( NSSTime *timeOpt, PRTime prTime) { NSSTime *rvTime; rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime); if (rvTime) { rvTime->prTime = prTime; } return rvTime; } NSS_IMPLEMENT PRTime NSSTime_GetPRTime( NSSTime *time) { return time->prTime; }