From 856a057fc0a0807e9c0dd2b11c04e1f1312bdb12 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sun, 29 Apr 2007 00:20:38 +0000 Subject: Fix tons of bugs and performance issues to better list the certificates. --- ckcapi-cert.c | 32 +++++++++-- ckcapi-object.c | 42 +++----------- ckcapi-session.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- ckcapi-util.c | 18 +++--- ckcapi-util.h | 4 +- ckcapi.c | 9 +-- ckcapi.h | 81 +++++++++++++++++---------- 7 files changed, 268 insertions(+), 85 deletions(-) diff --git a/ckcapi-cert.c b/ckcapi-cert.c index 672e189..0162983 100644 --- a/ckcapi-cert.c +++ b/ckcapi-cert.c @@ -440,7 +440,7 @@ static const CkCapiObjectVtable cert_object_vtable = { static CK_RV register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert, - CK_OBJECT_HANDLE_PTR id) + CkCapiObject** obj) { CertObject* cobj; CK_RV ret; @@ -485,21 +485,36 @@ register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert } ASSERT(cobj->obj.id != 0); - *id = cobj->obj.id; + *obj = &cobj->obj; return CKR_OK; } +static void +clear_object_data_for_store(CkCapiSession* sess, CkCapiObject* obj, + CkCapiObjectData* data, void* arg) +{ + const char* store = (const char*) arg; + CertObject *cobj = (CertObject*)obj; + + if(strcmp(cobj->store, store) == 0) + ckcapi_session_clear_object_data(sess, obj); +} + CK_RV ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name, CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr) { PCCERT_CONTEXT cert = NULL; - CK_OBJECT_HANDLE obj; + CkCapiObject* obj; HCERTSTORE store; CkCapiObjectData objdata; DWORD err; CK_RV ret = CKR_OK; + + /* Clear any loaded data for objects in this store */ + ckcapi_session_enum_object_data(sess, clear_object_data_for_store, (void*)store_name); + store = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); if(store == NULL) { @@ -525,7 +540,16 @@ ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name, if(ret != CKR_OK) break; - ckcapi_array_append(arr, obj); + ASSERT(obj); + + /* Store away the object data for performance reasons */ + objdata.data = (void*)CertDuplicateCertificateContext(cert); + if(objdata.data) { + if(ckcapi_session_set_object_data(sess, obj, &objdata) != CKR_OK) + CertFreeCertificateContext((PCCERT_CONTEXT)objdata.data); + } + + ckcapi_array_append(arr, obj->id); } } diff --git a/ckcapi-object.c b/ckcapi-object.c index da3a467..49da8eb 100644 --- a/ckcapi-object.c +++ b/ckcapi-object.c @@ -26,7 +26,7 @@ ckcapi_object_clear_all(void) if(object_hash) { - ckcapi_hash_free(object_hash); + ckcapi_hash_free(object_hash, NULL); object_hash = NULL; } @@ -45,6 +45,14 @@ ckcapi_object_clear_all(void) ckcapi_unlock_global(); } +CK_OBJECT_HANDLE +ckcapi_object_get_max_handle(void) +{ + if(!object_array) + return 0; + return object_array->len; +} + CkCapiObject* ckcapi_object_lookup(CkCapiSession* sess, CK_OBJECT_HANDLE obj) { @@ -165,38 +173,6 @@ ckcapi_object_register(CkCapiSession* sess, CkCapiObject* obj) } -CK_RV -ckcapi_object_load_data(CkCapiObject* obj, CkCapiObjectData* objdata) -{ - ASSERT(obj); - ASSERT(obj->id); - ASSERT(obj->obj_funcs.load_data); - - memset(objdata, 0, sizeof(*objdata)); - return (obj->obj_funcs.load_data)(obj, objdata); -} - -void -ckcapi_object_data_release(CkCapiObjectData* objdata) -{ - ASSERT(objdata->data_funcs.release); - (objdata->data_funcs.release)(objdata->data); - memset(objdata, 0, sizeof(*objdata)); -} - -CK_RV -ckcapi_object_load_data_for(CkCapiSession* sess, CK_OBJECT_HANDLE hand, - CkCapiObjectData* objdata) -{ - CkCapiObject* obj; - - obj = ckcapi_object_lookup(sess, hand); - if(!obj) - return CKR_OBJECT_HANDLE_INVALID; - - return ckcapi_object_load_data(obj, objdata); -} - enum { DATA_UNKNOWN = 0, diff --git a/ckcapi-session.c b/ckcapi-session.c index ce7e9d2..9f9a6e6 100644 --- a/ckcapi-session.c +++ b/ckcapi-session.c @@ -11,6 +11,13 @@ typedef struct _SessionList { /* These are protected by global_mutex */ static SessionList the_sessions = { NULL, 0 }; +static void +object_data_release(CkCapiObjectData* objdata) +{ + ASSERT(objdata->data_funcs.release); + (objdata->data_funcs.release)(objdata->data); + free(objdata); +} CkCapiSession* ckcapi_session_create(void) @@ -19,9 +26,15 @@ ckcapi_session_create(void) if(!sess) return NULL; + sess->object_data = ckcapi_hash_new(); + if(!sess->object_data) { + free(sess); + return NULL; + } + sess->mutex = CreateMutex(NULL, FALSE, NULL); - if(!sess->mutex) - { + if(!sess->mutex) { + ckcapi_hash_free(sess->object_data, NULL); free(sess); return NULL; } @@ -132,6 +145,10 @@ ckcapi_session_destroy(CkCapiSession* sess) ASSERT(sess->operation_data == NULL); ASSERT(sess->operation_cancel == NULL); + /* Make all the object adat go away */ + ASSERT(sess->object_data != NULL); + ckcapi_hash_free(sess->object_data, object_data_release); + /* And make the mutex go away */ ASSERT(sess->mutex != NULL); CloseHandle(sess->mutex); @@ -327,6 +344,150 @@ ckcapi_session_close_all() } } +/* ---------------------------------------------------------------------------- + * OBJECT DATA + */ + +CK_RV +ckcapi_object_load_data(CkCapiObject* obj, CkCapiObjectData* objdata) +{ + ASSERT(obj); + ASSERT(obj->id); + ASSERT(obj->obj_funcs.load_data); + + memset(objdata, 0, sizeof(*objdata)); + return (obj->obj_funcs.load_data)(obj, objdata); +} + +CK_RV +ckcapi_session_get_object_data(CkCapiSession* sess, CkCapiObject* obj, + CkCapiObjectData** objdata) +{ + CK_OBJECT_HANDLE id; + CkCapiObjectData* newdata; + CK_RV ret; + + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(obj); + ASSERT(obj->obj_funcs.load_data); + ASSERT(objdata); + + id = obj->id; + + *objdata = ckcapi_hash_get(sess->object_data, &id, sizeof(id)); + if(*objdata) + return CKR_OK; + + newdata = calloc(sizeof(CkCapiObjectData), 1); + if(!newdata) + return CKR_HOST_MEMORY; + + newdata->object = id; + ret = (obj->obj_funcs.load_data)(obj, newdata); + if(ret != CKR_OK) { + free(newdata); + return ret; + } + + if(!ckcapi_hash_set(sess->object_data, &newdata->object, + sizeof(newdata->object), newdata)) { + object_data_release(newdata); + return CKR_HOST_MEMORY; + } + + *objdata = newdata; + return CKR_OK; +} + +void +ckcapi_session_clear_object_data(CkCapiSession* sess, CkCapiObject* obj) +{ + CkCapiObjectData* objdata; + + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(obj); + + objdata = (CkCapiObjectData*)ckcapi_hash_rem(sess->object_data, &obj->id, sizeof(obj->id)); + if(objdata) + object_data_release(objdata); +} + +void +ckcapi_session_enum_object_data(CkCapiSession* sess, + CkCapiEnumObjectData enum_func, void* arg) +{ + CK_OBJECT_HANDLE i, max; + CkCapiObject* obj; + CkCapiObjectData* objdata; + + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(enum_func); + + max = ckcapi_object_get_max_handle(); + for(i = 0; i < max; ++i) + { + objdata = (CkCapiObjectData*)ckcapi_hash_get(sess->object_data, &i, sizeof(i)); + if(!objdata) + continue; + + obj = ckcapi_object_lookup (sess, i); + if(!obj) + continue; + + (enum_func)(sess, obj, objdata, arg); + } +} + +CK_RV +ckcapi_session_get_object_data_for(CkCapiSession* sess, CK_OBJECT_HANDLE hand, + CkCapiObjectData** objdata) +{ + CkCapiObject* obj; + + obj = ckcapi_object_lookup(sess, hand); + if(!obj) + return CKR_OBJECT_HANDLE_INVALID; + + return ckcapi_session_get_object_data(sess, obj, objdata); +} + +CK_RV +ckcapi_session_set_object_data(CkCapiSession* sess, CkCapiObject* obj, + const CkCapiObjectData* objdata) +{ + CkCapiObjectData* newdata; + CkCapiObjectData* prev; + + ASSERT(obj); + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(objdata); + + newdata = calloc(sizeof(CkCapiObjectData), 1); + if(!newdata) + return CKR_HOST_MEMORY; + + newdata->object = obj->id; + newdata->data = objdata->data; + newdata->data_funcs = objdata->data_funcs; + + prev = ckcapi_hash_rem(sess->object_data, &obj->id, sizeof(obj->id)); + if(prev) + object_data_release(prev); + + if(!ckcapi_hash_set(sess->object_data, &newdata->object, + sizeof(newdata->object), newdata)) { + free(newdata); + return CKR_HOST_MEMORY; + } + + return CKR_OK; +} + + /* ---------------------------------------------------------------------------- * FIND OPERATION */ @@ -420,7 +581,7 @@ purge_duplicate_ulongs(CkCapiArray* arr) } } - ckcapi_hash_free(checks); + ckcapi_hash_free(checks, NULL); } CK_RV diff --git a/ckcapi-util.c b/ckcapi-util.c index 3c587ac..7fd1d1d 100644 --- a/ckcapi-util.c +++ b/ckcapi-util.c @@ -202,7 +202,7 @@ typedef struct _HashEntry unsigned int hash; const void* key; size_t klen; - const void* val; + void* val; } HashEntry; @@ -252,17 +252,19 @@ ckcapi_hash_new() } void -ckcapi_hash_free(CkCapiHash* ht) +ckcapi_hash_free(CkCapiHash* ht, CkCapiHashDestroy destroy_func) { HashEntry* he; HashEntry* next; size_t i; - for(i = 0; i < ht->max; ++i) + for(i = 0; i <= ht->max; ++i) { for(he = ht->array[i]; he; ) { next = he->next; + if(destroy_func) + (destroy_func)((void*)he->val); free(he); he = next; } @@ -290,13 +292,13 @@ expand_array(CkCapiHash* ht) if(!new_array) return 0; - for(i = 0; i < ht->max; ++i) + for(i = 0; i <= ht->max; ++i) { for(he = ht->array[i]; he; he = he->next) { - unsigned int i = he->hash & new_max; - he->next = new_array[i]; - new_array[i] = he; + unsigned int j = he->hash & new_max; + he->next = new_array[j]; + new_array[j] = he; } } @@ -318,7 +320,7 @@ expand_array(CkCapiHash* ht) */ static HashEntry** -find_entry(CkCapiHash* ht, const void* key, size_t klen, const void* val) +find_entry(CkCapiHash* ht, const void* key, size_t klen, void* val) { HashEntry** hep; HashEntry* he; diff --git a/ckcapi-util.h b/ckcapi-util.h index ea3d5e2..84aa9bd 100644 --- a/ckcapi-util.h +++ b/ckcapi-util.h @@ -44,8 +44,10 @@ void ckcapi_array_remove_range (CkCapiArray* array, unsigned int index, struct _CkCapiHash; typedef struct _CkCapiHash CkCapiHash; +typedef void (*CkCapiHashDestroy)(void* val); + CkCapiHash* ckcapi_hash_new(); -void ckcapi_hash_free(CkCapiHash* ht); +void ckcapi_hash_free(CkCapiHash* ht, CkCapiHashDestroy destroy_func); size_t ckcapi_hash_count(CkCapiHash* ht); void* ckcapi_hash_get(CkCapiHash* ht, const void* key, size_t klen); int ckcapi_hash_set(CkCapiHash* ht, const void* key, size_t klen, void* val); diff --git a/ckcapi.c b/ckcapi.c index a1243b8..0bed282 100644 --- a/ckcapi.c +++ b/ckcapi.c @@ -582,7 +582,7 @@ CC_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR templ, CK_ULONG count) { CkCapiSession* sess; - CkCapiObjectData objdata; + CkCapiObjectData* objdata; CK_RV ret; ENTER(C_GetAttributeValue); @@ -593,12 +593,9 @@ CC_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, ret = ckcapi_session_get_lock_ref(session, 0, &sess); if(ret == CKR_OK) { - ret = ckcapi_object_load_data_for(sess, object, &objdata); + ret = ckcapi_session_get_object_data_for(sess, object, &objdata); if(ret == CKR_OK) - { - ret = ckcapi_object_data_get_attrs(&objdata, templ, count); - ckcapi_object_data_release(&objdata); - } + ret = ckcapi_object_data_get_attrs(objdata, templ, count); ckcapi_session_unref_unlock(sess); } diff --git a/ckcapi.h b/ckcapi.h index e1a0301..d6ee27b 100644 --- a/ckcapi.h +++ b/ckcapi.h @@ -18,6 +18,9 @@ struct _CkCapiObject; struct _CkCapiSession; +typedef struct _CkCapiObject CkCapiObject; +typedef struct _CkCapiSession CkCapiSession; + /* ------------------------------------------------------------------ * cryptoki-capi.c */ @@ -30,6 +33,32 @@ void ckcapi_lock_global(void); void ckcapi_unlock_global(void); CK_RV ckcapi_winerr_to_ckr (DWORD werr); +/* object data ------------------- */ + +typedef CK_RV (*CkCapiGetAttribute)(void* obj, CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR data, CK_ULONG_PTR len); + +typedef void (*CkCapiRelease)(void* value); + +typedef struct _CkCapiObjectDataVtable +{ + CkCapiGetAttribute get_bool; + CkCapiGetAttribute get_ulong; + CkCapiGetAttribute get_bytes; + CkCapiGetAttribute get_date; + CkCapiRelease release; +} +CkCapiObjectDataVtable; + +typedef struct _CkCapiObjectData +{ + CK_OBJECT_HANDLE object; + void* data; + CkCapiObjectDataVtable data_funcs; +} +CkCapiObjectData; + + /* ------------------------------------------------------------------ * cryptoki-capi-session.c */ @@ -52,6 +81,8 @@ typedef struct _CkCapiSession void* operation_data; /* Data for this operation */ CkCapiSessionCancel operation_cancel; /* Callback to cancel operation when necessary */ + CkCapiHash* object_data; + CK_NOTIFY notify_callback; /* Application specified callback */ CK_VOID_PTR user_data; /* Argument for above */ @@ -75,6 +106,22 @@ CK_RV ckcapi_session_find (CkCapiSession* sess, CK_OBJECT_HANDLE_PTR objects CK_ULONG max_object_count, CK_ULONG_PTR object_count); CK_RV ckcapi_session_find_final (CkCapiSession* sess); +CK_RV ckcapi_session_get_object_data (CkCapiSession* sess, CkCapiObject* obj, + CkCapiObjectData** objdata); + +CK_RV ckcapi_session_get_object_data_for (CkCapiSession* sess, CK_OBJECT_HANDLE hand, + CkCapiObjectData** objdata); + +CK_RV ckcapi_session_set_object_data (CkCapiSession* sess, CkCapiObject* obj, + const CkCapiObjectData* objdata); + +void ckcapi_session_clear_object_data (CkCapiSession* sess, CkCapiObject* obj); + +typedef void (*CkCapiEnumObjectData)(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData* data, void* arg); + +void ckcapi_session_enum_object_data (CkCapiSession* sess, CkCapiEnumObjectData enum_func, void* arg); + + /* ------------------------------------------------------------------ * ckcapi-object.c */ @@ -86,27 +133,6 @@ enum OBJECT_BUILTIN = 2 }; -typedef CK_RV (*CkCapiGetAttribute)(void* obj, CK_ATTRIBUTE_TYPE type, - CK_VOID_PTR data, CK_ULONG_PTR len); - -typedef void (*CkCapiRelease)(void* value); - -typedef struct _CkCapiObjectDataVtable -{ - CkCapiGetAttribute get_bool; - CkCapiGetAttribute get_ulong; - CkCapiGetAttribute get_bytes; - CkCapiGetAttribute get_date; - CkCapiRelease release; -} -CkCapiObjectDataVtable; - -typedef struct _CkCapiObjectData -{ - void* data; - CkCapiObjectDataVtable data_funcs; -} -CkCapiObjectData; typedef CK_RV (*CkCapiPurge)(struct _CkCapiObject* obj); typedef CK_RV (*CkCapiLoadData)(struct _CkCapiObject* obj, CkCapiObjectData* objdata); @@ -138,7 +164,7 @@ CkCapiObjectVtable; #define UNIQUE_KEY_VAR_LEN(obj, first, last, len) \ ((((char*)&((obj->last))) - ((char*)&((obj->first)))) + (len)) -typedef struct _CkCapiObject +struct _CkCapiObject { CK_OBJECT_HANDLE id; @@ -146,22 +172,19 @@ typedef struct _CkCapiObject CkCapiObjectVtable obj_funcs; void* unique_key; size_t unique_len; -} -CkCapiObject; +}; #define DBGO(obj, msg) \ ckcapi_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg)) +CK_OBJECT_HANDLE ckcapi_object_get_max_handle (void); + CkCapiObject* ckcapi_object_lookup (CkCapiSession* sess, CK_OBJECT_HANDLE obj); CK_RV ckcapi_object_register (CkCapiSession* sess, CkCapiObject* obj); void ckcapi_object_clear_all (void); -CK_RV ckcapi_object_load_data (CkCapiObject* obj, CkCapiObjectData* objdata); - -CK_RV ckcapi_object_load_data_for (CkCapiSession* sess, CK_OBJECT_HANDLE hand, - CkCapiObjectData* objdata); CK_BBOOL ckcapi_object_data_match (CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR matches, CK_ULONG count); @@ -172,8 +195,6 @@ CK_BBOOL ckcapi_object_data_match_attr (CkCapiObjectData* objdata, CK_RV ckcapi_object_data_get_attrs (CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attrs, CK_ULONG count); -void ckcapi_object_data_release (CkCapiObjectData* objdata); - /* ------------------------------------------------------------------- * ckcapi-cert.c */ -- cgit v1.2.3