#include "ckcapi.h" static CkCapiArray* object_array = NULL; static CkCapiHash* object_hash = NULL; typedef struct _SlotInfo { const char* capi_store; const char* display_name; CK_ULONG slot_flags; } SlotInfo; static const SlotInfo slot_info[] = { { "My", "Personal Certificates", CKCAPI_SLOT_TRUSTED }, { "AddressBook", "Address Book Certificates", 0 }, { "CA", "Certificate Authorities", CKCAPI_SLOT_CA }, { "Root", "Root Authorities", CKCAPI_SLOT_TRUSTED | CKCAPI_SLOT_CA }, { "Trust", "Trust", 0 }, { "TrustedPeople", "Trusted People", CKCAPI_SLOT_TRUSTED }, { "AuthRoot", "Auth Root", 0 }, }; unsigned int ckcapi_token_get_count(void) { return sizeof(slot_info) / sizeof(slot_info[0]); } CK_BBOOL ckcapi_token_is_valid(CK_SLOT_ID slot) { return slot >= 0 && slot < ckcapi_token_get_count(); } const char* ckcapi_token_get_display_name(CK_SLOT_ID slot) { ASSERT(ckcapi_token_is_valid(slot)); ASSERT(slot_info[slot].display_name); return slot_info[slot].display_name; } const char* ckcapi_token_get_store_name(CK_SLOT_ID slot) { ASSERT(ckcapi_token_is_valid(slot)); ASSERT(slot_info[slot].capi_store); return slot_info[slot].capi_store; } CK_ULONG ckcapi_token_get_flags(CK_SLOT_ID slot) { ASSERT(ckcapi_token_is_valid(slot)); return slot_info[slot].slot_flags; } static void object_free(CkCapiObject* obj) { ASSERT(obj); ASSERT(obj->obj_funcs); ASSERT(obj->obj_funcs->release); (obj->obj_funcs->release)(obj); } void ckcapi_token_cleanup_all(void) { size_t i; ckcapi_lock_global(); if(object_hash) { ckcapi_hash_free(object_hash, NULL); object_hash = NULL; } if(object_array) { for(i = 1; i < object_array->len; ++i) { ASSERT(ckcapi_array_index(object_array, CkCapiObject*, i)); object_free(ckcapi_array_index(object_array, CkCapiObject*, i)); } ckcapi_array_free(object_array, TRUE); object_array = NULL; } ckcapi_unlock_global(); } CK_OBJECT_HANDLE ckcapi_token_get_max_handle(void) { if(!object_array) return 0; return object_array->len; } CkCapiObject* ckcapi_token_lookup_object(CK_SLOT_ID slot, CK_OBJECT_HANDLE obj) { /* This must be called without any locks held */ CkCapiObject* ret = NULL; ASSERT(slot); ASSERT(obj > 0); ckcapi_lock_global(); if(object_array && obj < object_array->len) ret = ckcapi_array_index(object_array, CkCapiObject*, obj); ckcapi_unlock_global(); /* Must belong to the right slot */ if(ret && ret->slot != slot) ret = NULL; return ret; } CK_RV ckcapi_token_register_object(CK_SLOT_ID slot, CkCapiObject* obj) { CkCapiObject* prev; CK_RV ret = CKR_OK; void* key; size_t klen; ASSERT(slot); ASSERT(obj->id == 0); ASSERT(obj->unique_key); ASSERT(obj->unique_len > 0); DBG(("registering object")); ckcapi_lock_global(); if(!object_array) { object_array = ckcapi_array_sized_new(0, 1, sizeof(CkCapiObject*), 16); if(object_array) { /* A blank entry for '0' */ CkCapiObject* blank = NULL; ckcapi_array_append(object_array, blank); } object_hash = ckcapi_hash_new(); if(!object_array || !object_hash) { /* Allocation failed above */ ret = CKR_HOST_MEMORY; } } if(ret == CKR_OK) { ASSERT(object_array); ASSERT(object_hash); /* The type of object is part of the hash */ key = obj->unique_key; klen = obj->unique_len; /* Sanity check, in case calcs went wrong somewhere */ ASSERT(klen < 0xFFFFFF); /* xxxxx hash function xxxxx */ /* Look in the hash and find a previous object */ prev = ckcapi_hash_get(object_hash, key, klen); if(prev) { /* Register it in the previous object's place */ obj->id = prev->id; ASSERT(prev->id < object_array->len); if(ckcapi_hash_set(object_hash, key, klen, obj)) { ckcapi_array_index(object_array, CkCapiObject*, obj->id) = obj; object_free(prev); DBGO(obj, "found old object id"); } else { ret = CKR_HOST_MEMORY; } } else { /* Register it at the end of the array */ obj->id = object_array->len; ASSERT(obj->id > 0); if(ckcapi_hash_set(object_hash, key, klen, obj)) { if(ckcapi_array_append(object_array, obj)) { DBGO(obj, "registered new object id"); } else { ret = CKR_HOST_MEMORY; /* Roll back our addition */ ckcapi_hash_rem(object_hash, key, klen); } } else { ret = CKR_HOST_MEMORY; } } } if(ret == CKR_OK) obj->slot = slot; ckcapi_unlock_global(); return ret; }