From c6d18eea781bc98a362595e2334223b48f41b522 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 11 May 2007 17:07:19 +0000 Subject: Add different tokens for different certificate stores. --- ckcapi-builtin.c | 42 ++++++---- ckcapi-cert.c | 127 +++++++----------------------- ckcapi-object.c | 168 ---------------------------------------- ckcapi-session.c | 204 +++++++++++++++++++++++++++++------------------- ckcapi-token.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ckcapi-trust.c | 4 +- ckcapi.c | 81 ++++++++++++-------- ckcapi.dsp | 4 + ckcapi.h | 113 ++++++++++++++++----------- 9 files changed, 533 insertions(+), 440 deletions(-) create mode 100644 ckcapi-token.c diff --git a/ckcapi-builtin.c b/ckcapi-builtin.c index 6788701..26e9cd9 100644 --- a/ckcapi-builtin.c +++ b/ckcapi-builtin.c @@ -46,9 +46,16 @@ static const CK_ATTRIBUTE builtin_root[] = { { CK_END_LIST, NULL, 0 } }; -static const CK_ATTRIBUTE_PTR all_builtins[] = { - (CK_ATTRIBUTE_PTR)&builtin_root, - NULL, +typedef struct _BuiltinMatch +{ + CK_ATTRIBUTE_PTR attr; + CK_ULONG slot_flags; +} +BuiltinMatch; + +static const BuiltinMatch all_builtins[] = { + { (CK_ATTRIBUTE_PTR)&builtin_root, CKCAPI_SLOT_TRUSTED | CKCAPI_SLOT_CA }, + { NULL, 0 } }; /* This is filled in later */ @@ -68,7 +75,7 @@ typedef struct _BuiltinObject * laid out together in memory. */ unsigned int otype; - CK_ULONG builtin_index; + CK_ATTRIBUTE_PTR attr; } BuiltinObject; @@ -144,14 +151,12 @@ builtin_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData** obj ASSERT(objdata); ASSERT(num_builtins > 0); - if(bobj->builtin_index > num_builtins) - return CKR_OBJECT_HANDLE_INVALID; - bdata = (BuiltinObjectData*)calloc(sizeof(BuiltinObjectData), 1); if(!bdata) return CKR_HOST_MEMORY; - bdata->attr = all_builtins[bobj->builtin_index]; + /* Simple, just use same data */ + bdata->attr = bobj->attr; bdata->base.object = obj->id; bdata->base.data_funcs = &builtin_objdata_vtable; @@ -174,7 +179,7 @@ static const CkCapiObjectVtable builtin_object_vtable = { }; static CK_RV -register_builtin_object(CkCapiSession* sess, CK_ULONG index, CkCapiObject** obj) +register_builtin_object(CkCapiSession* sess, CK_ATTRIBUTE_PTR attr, CkCapiObject** obj) { BuiltinObject* bobj; CK_RV ret; @@ -184,14 +189,14 @@ register_builtin_object(CkCapiSession* sess, CK_ULONG index, CkCapiObject** obj) return CKR_HOST_MEMORY; bobj->otype = OBJECT_BUILTIN; - bobj->builtin_index = index; + bobj->attr = attr; bobj->obj.id = 0; bobj->obj.obj_funcs = &builtin_object_vtable; bobj->obj.unique_key = UNIQUE_KEY_AT(bobj, otype); - bobj->obj.unique_len = UNIQUE_KEY_LEN(bobj, otype, builtin_index); + bobj->obj.unique_len = UNIQUE_KEY_LEN(bobj, otype, attr); - ret = ckcapi_object_register(sess, &(bobj->obj)); + ret = ckcapi_token_register_object(sess->slot, &(bobj->obj)); if(ret != CKR_OK) { free(bobj); @@ -210,12 +215,12 @@ ckcapi_builtin_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR m CkCapiObject* obj; BuiltinObjectData bdata; CK_RV ret = CKR_OK; - CK_ULONG i; + CK_ULONG i, fl; /* First time around count total number */ if(!num_builtins) { - while(all_builtins[num_builtins]) + while(all_builtins[num_builtins].attr) ++num_builtins; ASSERT(num_builtins > 0); } @@ -223,13 +228,18 @@ ckcapi_builtin_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR m /* Match each certificate */ for(i = 0; i < num_builtins; ++i) { - bdata.attr = all_builtins[i]; + /* Only apply built in objects to appropriate slots */ + fl = ckcapi_token_get_flags(sess->slot) & all_builtins[i].slot_flags; + if(fl != all_builtins[i].slot_flags) + continue; + + bdata.attr = all_builtins[i].attr; bdata.base.object = 0; bdata.base.data_funcs = &builtin_objdata_vtable; if(ckcapi_object_data_match(&bdata.base, match, count)) { - ret = register_builtin_object(sess, i, &obj); + ret = register_builtin_object(sess, all_builtins[i].attr, &obj); if(ret != CKR_OK) break; diff --git a/ckcapi-cert.c b/ckcapi-cert.c index 0e40905..15ab880 100644 --- a/ckcapi-cert.c +++ b/ckcapi-cert.c @@ -31,22 +31,9 @@ #define USE_ENCODINGS (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) -/* All the stores we look in for certificates, in this order */ -static const char* CERT_STORES[] = { - "My", - "AddressBook", - "CA", - "Root", - "Trust", - "TrustedPeople", - "AuthRoot", - NULL -}; - typedef struct _CertObject { CkCapiObject obj; - const char* store; /* Together these can uniquely identify a certificate */ CRYPT_INTEGER_BLOB serial; @@ -238,31 +225,26 @@ static CK_RV cert_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData** objdata) { CertObject* cobj = (CertObject*)obj; - HCERTSTORE store; CERT_INFO info; PCCERT_CONTEXT cert; ASSERT(cobj); ASSERT(objdata); - ASSERT(cobj->store); - store = CertOpenSystemStore((HCRYPTPROV)NULL, cobj->store); - if(!store) - return ckcapi_winerr_to_ckr(GetLastError()); - ASSERT(cobj->issuer.pbData); ASSERT(cobj->issuer.cbData); ASSERT(cobj->serial.pbData); ASSERT(cobj->serial.cbData); + /* No store should mean no objects were loaded */ + ASSERT(sess->store); + /* Setup our search */ memset(&info, 0, sizeof(info)); memcpy(&info.SerialNumber, &cobj->serial, sizeof(info.SerialNumber)); memcpy(&info.Issuer, &cobj->issuer, sizeof(info.Issuer)); - cert = CertGetSubjectCertificateFromStore(store, USE_ENCODINGS, &info); - - CertCloseStore(store, 0); + cert = CertGetSubjectCertificateFromStore(sess->store, USE_ENCODINGS, &info); if(!cert) { @@ -481,8 +463,7 @@ ckcapi_cert_object_data_get_certificate(CkCapiObjectData* objdata) } static CK_RV -register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert, - CkCapiObject** obj) +register_cert_object(CkCapiSession* sess, PCCERT_CONTEXT cert, CkCapiObject** obj) { CertObject* cobj; CK_RV ret; @@ -500,7 +481,6 @@ register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert return CKR_HOST_MEMORY; cobj->otype = OBJECT_CERT; - cobj->store = store; cobj->obj.id = 0; cobj->obj.unique_key = UNIQUE_KEY_AT(cobj, otype); @@ -519,7 +499,7 @@ register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert memcpy(cobj->serial.pbData, cert->pCertInfo->SerialNumber.pbData, cobj->serial.cbData); - ret = ckcapi_object_register(sess, &(cobj->obj)); + ret = ckcapi_token_register_object(sess->slot, &(cobj->obj)); if(ret != CKR_OK) { free(cobj); @@ -531,52 +511,22 @@ register_cert_object(CkCapiSession* sess, const char* store, PCCERT_CONTEXT cert 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; - - // Is it one of ours? - if(obj->obj_funcs != &cert_object_vtable) - return; - - if(strcmp(cobj->store, store) == 0) - ckcapi_session_clear_object_data(sess, obj); -} - static CK_RV -find_in_store(CkCapiSession* sess, const char* store_name, - CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr) +find_in_store(CkCapiSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count, CkCapiArray* arr) { PCCERT_CONTEXT cert = NULL; CkCapiObject* obj; - HCERTSTORE store; CertObjectData cdata; 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) - { - err = GetLastError(); - - /* Store not found, we don't care */ - if(err == ERROR_FILE_NOT_FOUND) - return CKR_OK; - - else - return ckcapi_winerr_to_ckr(err); - } + /* No store, no objects */ + if(!sess->store) + return CKR_OK; /* Match each certificate */ - while((cert = CertEnumCertificatesInStore(store, cert)) != NULL) + while((cert = CertEnumCertificatesInStore(sess->store, cert)) != NULL) { cdata.cert = cert; cdata.base.object = 0; @@ -584,7 +534,7 @@ find_in_store(CkCapiSession* sess, const char* store_name, if(ckcapi_object_data_match(&cdata.base, match, count)) { - ret = register_cert_object(sess, store_name, cert, &obj); + ret = register_cert_object(sess, cert, &obj); if(ret != CKR_OK) break; @@ -604,37 +554,25 @@ find_in_store(CkCapiSession* sess, const char* store_name, } } - ASSERT(store); - CertCloseStore(store, 0); - return ret; } static CK_RV -match_in_store(CkCapiSession* sess, const char* store_name, PCERT_INFO info, - CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr) +match_in_store(CkCapiSession* sess, PCERT_INFO info, CK_ATTRIBUTE_PTR match, + CK_ULONG count, CkCapiArray* arr) { PCCERT_CONTEXT cert = NULL; CkCapiObject* obj; CkCapiObjectData* objdata; - HCERTSTORE store; CertObjectData cdata; DWORD err; CK_RV ret = CKR_OK; - store = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); - if(store == NULL) - { - err = GetLastError(); - - /* Store not found, we don't care */ - if(err == ERROR_FILE_NOT_FOUND) - return CKR_OK; - else - return ckcapi_winerr_to_ckr(err); - } + /* No store, no objects */ + if(!sess->store) + return CKR_OK; - cert = CertGetSubjectCertificateFromStore(store, USE_ENCODINGS, info); + cert = CertGetSubjectCertificateFromStore(sess->store, USE_ENCODINGS, info); if(cert == NULL) { err = GetLastError(); @@ -653,7 +591,7 @@ match_in_store(CkCapiSession* sess, const char* store_name, PCERT_INFO info, if(ckcapi_object_data_match(&cdata.base, match, count)) { - ret = register_cert_object(sess, store_name, cert, &obj); + ret = register_cert_object(sess, cert, &obj); if(ret == CKR_OK) { ASSERT(obj); @@ -669,10 +607,6 @@ match_in_store(CkCapiSession* sess, const char* store_name, PCERT_INFO info, if(ret != CKR_OK && cert) CertFreeCertificateContext(cert); - - ASSERT(store); - CertCloseStore(store, 0); - return ret; } @@ -683,7 +617,6 @@ ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR matc CRYPT_INTEGER_BLOB* serial = NULL; CERT_INFO info; CK_RV ret; - BOOL specific; CK_ULONG i; DWORD size; @@ -728,21 +661,13 @@ ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR matc } } - specific = info.SerialNumber.cbData && info.Issuer.cbData; + /* Match a specific certificate */ + if(info.SerialNumber.cbData && info.Issuer.cbData) + ret = match_in_store(sess, &info, match, count, arr); - for(i = 0; CERT_STORES[i]; ++i) - { - /* Match a specific certificate */ - if(specific) - ret = match_in_store(sess, CERT_STORES[i], &info, match, count, arr); - - /* Match any ol certificate */ - else - ret = find_in_store(sess, CERT_STORES[i], match, count, arr); - - if(ret != CKR_OK) - break; - } + /* Match any ol certificate */ + else + ret = find_in_store(sess, match, count, arr); if(serial) free(serial); diff --git a/ckcapi-object.c b/ckcapi-object.c index 6d8bb86..051baf4 100644 --- a/ckcapi-object.c +++ b/ckcapi-object.c @@ -23,174 +23,6 @@ #include -static CkCapiArray* object_array = NULL; -static CkCapiHash* object_hash = NULL; - -static void -object_free(CkCapiObject* obj) -{ - ASSERT(obj); - ASSERT(obj->obj_funcs); - ASSERT(obj->obj_funcs->release); - (obj->obj_funcs->release)(obj); -} - -void -ckcapi_object_clear_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_object_get_max_handle(void) -{ - if(!object_array) - return 0; - return object_array->len; -} - -CkCapiObject* -ckcapi_object_lookup(CkCapiSession* sess, CK_OBJECT_HANDLE obj) -{ - /* This must be called without any locks held */ - - CkCapiObject* ret = NULL; - - ASSERT(sess); - ASSERT(obj > 0); - - ckcapi_lock_global(); - - if(object_array && obj < object_array->len) - ret = ckcapi_array_index(object_array, CkCapiObject*, obj); - - ckcapi_unlock_global(); - - return ret; -} - -CK_RV -ckcapi_object_register(CkCapiSession* sess, CkCapiObject* obj) -{ - CkCapiObject* prev; - CK_RV ret = CKR_OK; - void* key; - size_t klen; - - ASSERT(sess); - 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); - - /* 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; - } - } - } - - ckcapi_unlock_global(); - - return ret; - -} - enum { DATA_UNKNOWN = 0, diff --git a/ckcapi-session.c b/ckcapi-session.c index 0e9316f..0d71fe2 100644 --- a/ckcapi-session.c +++ b/ckcapi-session.c @@ -21,13 +21,7 @@ #include "ckcapi.h" -typedef struct _SessionList { - CkCapiSession **list; - size_t lmax; -} SessionList; - -/* These are protected by global_mutex */ -static SessionList the_sessions = { NULL, 0 }; +static CkCapiArray* all_sessions = NULL; static void object_data_release(CkCapiObjectData* objdata) @@ -37,34 +31,58 @@ object_data_release(CkCapiObjectData* objdata) (objdata->data_funcs->release)(objdata); } -CkCapiSession* -ckcapi_session_create(void) +CK_RV +ckcapi_session_create(CK_SLOT_ID slot, CkCapiSession** ret) { - CkCapiSession* sess = calloc(1, sizeof(CkCapiSession)); + CkCapiSession* sess; + DWORD err; + + sess = calloc(1, sizeof(CkCapiSession)); if(!sess) - return NULL; + return CKR_HOST_MEMORY; sess->object_data = ckcapi_hash_new(); if(!sess->object_data) { free(sess); - return NULL; + return CKR_HOST_MEMORY; } sess->mutex = CreateMutex(NULL, FALSE, NULL); if(!sess->mutex) { ckcapi_hash_free(sess->object_data, NULL); free(sess); - return NULL; + return CKR_HOST_MEMORY; + } + + sess->store = CertOpenSystemStore((HCRYPTPROV)NULL, + ckcapi_token_get_store_name(slot)); + if(sess->store == NULL) + { + err = GetLastError(); + + /* Store not found, we don't care */ + if(err != ERROR_FILE_NOT_FOUND) + { + ckcapi_hash_free(sess->object_data, NULL); + CloseHandle(sess->mutex); + free(sess); + return ckcapi_winerr_to_ckr(err); + } } + sess->slot = slot; + DBGS(sess, "created"); - return sess; + + *ret = sess; + return CKR_OK; } CK_RV ckcapi_session_register(CkCapiSession* sess) { - CK_ULONG id = 0; + CkCapiSession* blank = NULL; + CK_SESSION_HANDLE id = 0; CK_RV ret = CKR_OK; size_t i; @@ -78,6 +96,22 @@ ckcapi_session_register(CkCapiSession* sess) /* Find a nice session identifier */ while(id == 0) { + /* Allocate sessions properly */ + if(!all_sessions) + { + all_sessions = ckcapi_array_new(0, 1, sizeof(CkCapiSession*)); + if(!all_sessions) + { + ret = CKR_HOST_MEMORY; + break; + } + + /* A blank entry for '0' */ + ckcapi_array_append(all_sessions, blank); + + DBG(("allocated new session list")); + } + /* * PKCS#11 GRAY AREA: We're assuming we can reuse session * handles. PKCS#11 spec says they're like file handles, @@ -85,53 +119,32 @@ ckcapi_session_register(CkCapiSession* sess) */ /* Note we never put anything in array position '0' */ - for(i = 1; i < the_sessions.lmax; ++i) + for(i = 1; i < all_sessions->len; ++i) { /* Any empty position will do */ - if(!the_sessions.list[i]) + if(!ckcapi_array_index(all_sessions, CkCapiSession*, i)) { id = i; break; } } - /* Couldn't find a handle, reallocate */ - if(id == 0) + /* Couldn't find a handle, append a handle */ + if(id == 0) { - CkCapiSession** buf; - size_t oldmax, newmax; - - oldmax = the_sessions.lmax; - newmax = oldmax + 16; - - buf = realloc(the_sessions.list, newmax * sizeof(CkCapiSession*)); - if(!buf) - { - DBGS(sess, ("couldn't allocate session list, out of memory")); - ret = CKR_HOST_MEMORY; - break; - } - - /* Choose the first of the new block as the id */ - id = oldmax; - - /* Clear new memory */ - the_sessions.list = buf; - for( ; oldmax < newmax; ++oldmax) - buf[oldmax] = NULL; - the_sessions.lmax = newmax; - - DBG(("allocated new session list: %d max", newmax)); + id = all_sessions->len; + ckcapi_array_append(all_sessions, blank); } } if(ret == CKR_OK) { - ASSERT(id > 0 && id < the_sessions.lmax); - ASSERT(the_sessions.list[id] == NULL); + ASSERT(id > 0 && id < all_sessions->len); + ASSERT(!ckcapi_array_index(all_sessions, CkCapiSession*, id)); + /* And assign it to the session handle */ - the_sessions.list[id] = sess; + ckcapi_array_index(all_sessions, CkCapiSession*, i) = sess; sess->id = id; /* The session list reference */ @@ -163,6 +176,9 @@ ckcapi_session_destroy(CkCapiSession* sess) ASSERT(sess->operation_data == NULL); ASSERT(sess->operation_cancel == NULL); + if(sess->store) + CertCloseStore(sess->store, 0); + /* Make all the object adat go away */ ASSERT(sess->object_data != NULL); ckcapi_hash_free(sess->object_data, object_data_release); @@ -176,7 +192,7 @@ ckcapi_session_destroy(CkCapiSession* sess) } static CK_RV -lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, +lock_ref_internal(CkCapiArray* sessions, CK_SESSION_HANDLE id, int remove, CkCapiSession** sess_ret) { CkCapiSession *sess; @@ -185,15 +201,15 @@ lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, ASSERT(sessions); ASSERT(sess_ret); - if(id >= sessions->lmax) + if(id >= sessions->len) { DBG(("invalid session id: %d", id)); return CKR_SESSION_HANDLE_INVALID; } /* A seemingly valid id */ - ASSERT(sessions->list); - sess = sessions->list[id]; + ASSERT(sessions); + sess = ckcapi_array_index(sessions, CkCapiSession*, id); if(!sess) { @@ -241,7 +257,7 @@ lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id, /* And remove it if necessary */ if(remove) { - sessions->list[id] = NULL; + ckcapi_array_index(sessions, CkCapiSession*, id) = NULL; /* The session list reference */ sess->refs--; @@ -276,7 +292,7 @@ ckcapi_session_get_lock_ref(CK_ULONG id, int remove, CkCapiSession **sess) ckcapi_lock_global(); - ret = lock_ref_internal (&the_sessions, id, remove, sess); + ret = lock_ref_internal (all_sessions, id, remove, sess); ckcapi_unlock_global(); @@ -313,15 +329,15 @@ ckcapi_session_unref_unlock(CkCapiSession* sess) ckcapi_session_destroy(sess); } -void -ckcapi_session_close_all() +CK_RV +ckcapi_session_close_all(CK_SLOT_ID slot) { /* This must be called without any locks held */ - SessionList sessions; + CkCapiArray* sessions; CkCapiSession *sess; size_t i; - CK_RV ret; + CK_RV ret = CKR_OK; /* * PKCS#11 GRAY AREA: What happens when this gets called @@ -329,37 +345,71 @@ ckcapi_session_close_all() * because by the time it returns, all sessions should be closed. */ + DBG(("closing all sessions for: %d", slot)); + ckcapi_lock_global(); + sessions = ckcapi_array_sized_new(0, 1, sizeof(CkCapiSession*), + all_sessions->len); + if(!sessions) + ret = CKR_HOST_MEMORY; + /* Steal all the session data */ - sessions.list = the_sessions.list; - the_sessions.list = NULL; - sessions.lmax = the_sessions.lmax; - the_sessions.lmax = 0; - - if(sessions.list || sessions.lmax) - DBG(("closing all sessions")); + if(ret == CKR_OK) + { + for(i = 0; i < all_sessions->len; ++i) + { + sess = ckcapi_array_index(all_sessions, CkCapiSession*, i); + if(sess && (slot == ((CK_SLOT_ID)-1) || sess->slot == slot)) + { + /* Steal this session */ + ckcapi_array_index(all_sessions, CkCapiSession*, i) = NULL; + } + else + { + /* Not a session we're interested in */ + sess = NULL; + } + + /* Both null and normal sessions are set to preserve indexes */ + ckcapi_array_append(sessions, sess); + } + + ASSERT(sessions->len == all_sessions->len); + } ckcapi_unlock_global(); + if(ret != CKR_OK) + return ret; + /* Close each session in turn */ - for(i = 1; i < sessions.lmax; ++i) + for(i = 0; i < sessions->len; ++i) { - if(!sessions.list[i]) + if(!ckcapi_array_index(sessions, CkCapiSession*, i)) continue; - - ret = lock_ref_internal (&sessions, i, 1, &sess); - ASSERT(ret == CKR_OK); - ckcapi_session_unref_unlock(sess); + /* We need any calls in other threads to finish, so wait here */ + if(lock_ref_internal(sessions, i, 1, &sess) == CKR_OK) + ckcapi_session_unref_unlock(sess); } /* We stole the memory above, free it now */ - if(sessions.list) - { - free(sessions.list); - DBG(("freed session list")); - } + ckcapi_array_free(sessions, 1); + return CKR_OK; +} + +void +ckcapi_session_cleanup_all() +{ + ckcapi_session_close_all((CK_SLOT_ID)-1); + + ckcapi_lock_global(); + + ckcapi_array_free(all_sessions, 1); + all_sessions = NULL; + + ckcapi_unlock_global(); } /* ---------------------------------------------------------------------------- @@ -430,14 +480,14 @@ ckcapi_session_enum_object_data(CkCapiSession* sess, ASSERT(sess->object_data); ASSERT(enum_func); - max = ckcapi_object_get_max_handle(); + max = ckcapi_token_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); + obj = ckcapi_token_lookup_object(sess->slot, i); if(!obj) continue; @@ -451,7 +501,7 @@ ckcapi_session_get_object_data_for(CkCapiSession* sess, CK_OBJECT_HANDLE hand, { CkCapiObject* obj; - obj = ckcapi_object_lookup(sess, hand); + obj = ckcapi_token_lookup_object(sess->slot, hand); if(!obj) return CKR_OBJECT_HANDLE_INVALID; diff --git a/ckcapi-token.c b/ckcapi-token.c new file mode 100644 index 0000000..d7ef75a --- /dev/null +++ b/ckcapi-token.c @@ -0,0 +1,230 @@ + +#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; + +} diff --git a/ckcapi-trust.c b/ckcapi-trust.c index 9ab0412..30e1200 100644 --- a/ckcapi-trust.c +++ b/ckcapi-trust.c @@ -372,7 +372,7 @@ register_trust_object(CkCapiSession* sess, CkCapiObject* cert, CkCapiObject** ob tobj->obj.unique_key = UNIQUE_KEY_AT(tobj, otype); tobj->obj.unique_len = UNIQUE_KEY_LEN(tobj, otype, cert_obj); - ret = ckcapi_object_register(sess, &(tobj->obj)); + ret = ckcapi_token_register_object(sess->slot, &(tobj->obj)); if(ret != CKR_OK) { free(tobj); @@ -449,7 +449,7 @@ ckcapi_trust_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, id = ckcapi_array_index(certarr, CK_OBJECT_HANDLE, i); ASSERT(id); - certobj = ckcapi_object_lookup (sess, id); + certobj = ckcapi_token_lookup_object(sess->slot, id); ASSERT(certobj); /* We'll register a trust object for any loaded certificate */ diff --git a/ckcapi.c b/ckcapi.c index 4635a3f..1a398b3 100644 --- a/ckcapi.c +++ b/ckcapi.c @@ -27,7 +27,6 @@ * GLOBALS / DEFINES */ -static CK_ULONG slot_id = 33; /* arbitrary */ static int cryptoki_initialized = 0; static HANDLE global_mutex = NULL; @@ -35,7 +34,6 @@ static HANDLE global_mutex = NULL; #define LIBRARY_DESCRIPTION "Cryptoki CAPI Provider " #define LIBRARY_VERSION_MAJOR 1 #define LIBRARY_VERSION_MINOR 1 -#define SLOT_DESCRIPTION "Windows Certificates and Keys " #define HARDWARE_VERSION_MAJOR 0 #define HARDWARE_VERSION_MINOR 0 #define FIRMWARE_VERSION_MAJOR 0 @@ -202,8 +200,8 @@ CC_C_Finalize(CK_VOID_PTR pReserved) cryptoki_initialized = 0; - ckcapi_session_close_all(); - ckcapi_object_clear_all(); + ckcapi_session_cleanup_all(); + ckcapi_token_cleanup_all(); RETURN(CKR_OK); } @@ -239,46 +237,51 @@ CC_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) static CK_RV CC_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count) { + unsigned int n_tokens, i; + ENTER(C_GetSlotList); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(count, CKR_ARGUMENTS_BAD); - /* Token is always present */ + /* All tokens are always present */ + + n_tokens = ckcapi_token_get_count(); /* Application only wants to know the number of slots. */ if(slot_list == NULL) { - *count = 1; + *count = n_tokens; RETURN(CKR_OK); } - if((*count < 1) && (slot_list != NULL)) + if(*count < n_tokens) { - *count = 1; + *count = n_tokens; RETURN(CKR_BUFFER_TOO_SMALL); } - *count = 1; - slot_list[0] = slot_id; + *count = n_tokens; + for(i = 0; i < n_tokens; ++i) + slot_list[i] = i; RETURN(CKR_OK); } static CK_RV CC_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info) { + const char* name; + ENTER(C_GetSlotInfo); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(info, CKR_ARGUMENTS_BAD); /* Make sure the slot ID is valid */ - if(id != slot_id) + if(!ckcapi_token_is_valid(id)) RETURN(CKR_SLOT_ID_INVALID); - ASSERT(strlen(SLOT_DESCRIPTION) == 64); ASSERT(strlen(MANUFACTURER_ID) == 32); /* Provide information about the slot in the provided buffer */ - strncpy((char*)info->slotDescription, SLOT_DESCRIPTION, 64); strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); info->hardwareVersion.major = HARDWARE_VERSION_MAJOR; info->hardwareVersion.minor = HARDWARE_VERSION_MINOR; @@ -288,27 +291,34 @@ CC_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info) /* Token is always present */ info->flags = CKF_TOKEN_PRESENT; + /* Slot name is blank padded, odd */ + name = ckcapi_token_get_display_name(id); + memset((char*)info->slotDescription, ' ', + sizeof(info->slotDescription)); + memcpy((char*)info->slotDescription, name, + min(strlen(name), sizeof(info->slotDescription))); + RETURN(CKR_OK); } static CK_RV CC_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info) { + const char* name; + ENTER(C_GetTokenInfo); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(info, CKR_ARGUMENTS_BAD); /* Make sure the slot ID is valid */ - if(id != slot_id) + if(!ckcapi_token_is_valid(id)) RETURN(CKR_SLOT_ID_INVALID); - - ASSERT(strlen(SLOT_DESCRIPTION) == 64); + ASSERT(strlen(MANUFACTURER_ID) == 32); ASSERT(strlen(SLOT_TOKEN_MODEL) == 16); ASSERT(strlen(SLOT_TOKEN_SERIAL) == 16); /* Provide information about a token in the provided buffer */ - strncpy((char*)info->label, SLOT_DESCRIPTION, 32); strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32); strncpy((char*)info->model, SLOT_TOKEN_MODEL, 16); strncpy((char*)info->serialNumber, SLOT_TOKEN_SERIAL, 16); @@ -331,6 +341,12 @@ CC_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info) info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR; memset(info->utcTime, ' ', 16); + /* Slot name is blank padded, odd */ + name = ckcapi_token_get_display_name(id); + memset((char*)info->label, ' ', sizeof(info->label)); + memcpy((char*)info->label, name, + min(strlen(name), sizeof(info->label))); + RETURN(CKR_OK); } @@ -342,9 +358,12 @@ CC_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list, PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(count, CKR_ARGUMENTS_BAD); - if(id != slot_id) + if(!ckcapi_token_is_valid(id)) RETURN(CKR_SLOT_ID_INVALID); + /* TODO: Eventually we'll return stuff here */ + /* mechanism_list[0] = CKM_RSA_PKCS; */ + if(mechanism_list == NULL) { *count = 0; @@ -357,7 +376,6 @@ CC_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list, RETURN(CKR_BUFFER_TOO_SMALL); } - /* mechanism_list[0] = CKM_RSA_PKCS; */ *count = 0; RETURN(CKR_OK); } @@ -370,17 +388,16 @@ CC_C_GetMechanismInfo(CK_SLOT_ID id, CK_MECHANISM_TYPE type, PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(info, CKR_ARGUMENTS_BAD); - if(id != slot_id) + if(!ckcapi_token_is_valid(id)) RETURN(CKR_SLOT_ID_INVALID); - /* unsupported mechanism */ - if(type != CKM_RSA_PKCS) - RETURN(CKR_MECHANISM_INVALID); + /* TODO: Eventually we'll return stuff here */ + RETURN(CKR_MECHANISM_INVALID); - info->ulMinKeySize = 384; + /* info->ulMinKeySize = 384; info->ulMaxKeySize = 16384; - info->flags = 0; /* TODO: Choose which we'll implement */ - RETURN(CKR_OK); + info->flags = 0; + RETURN(CKR_OK);*/ } static CK_RV @@ -421,12 +438,12 @@ CC_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR application, ENTER(C_OpenSession); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - if(id != slot_id) + if(!ckcapi_token_is_valid(id)) RETURN(CKR_SLOT_ID_INVALID); - sess = ckcapi_session_create(); - if(sess == NULL) - RETURN(CKR_HOST_MEMORY); + ret = ckcapi_session_create(id, &sess); + if(ret != CKR_OK) + RETURN(ret); sess->notify_callback = notify; sess->user_data = application; @@ -472,10 +489,10 @@ CC_C_CloseAllSessions(CK_SLOT_ID id) ENTER(C_CloseAllSession); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - if(id != slot_id) + if(!ckcapi_token_is_valid(id)) RETURN(CKR_SLOT_ID_INVALID); - ckcapi_session_close_all(); + ckcapi_session_close_all(id); RETURN(CKR_OK); } diff --git a/ckcapi.dsp b/ckcapi.dsp index e417998..4394881 100644 --- a/ckcapi.dsp +++ b/ckcapi.dsp @@ -108,6 +108,10 @@ SOURCE=".\ckcapi-session.c" # End Source File # Begin Source File +SOURCE=".\ckcapi-token.c" +# End Source File +# Begin Source File + SOURCE=".\ckcapi-trust.c" # End Source File # Begin Source File diff --git a/ckcapi.h b/ckcapi.h index b6b8daf..4ccd1cb 100644 --- a/ckcapi.h +++ b/ckcapi.h @@ -48,14 +48,74 @@ #include "ckcapi-util.h" +struct _CkCapiSlot; struct _CkCapiObject; struct _CkCapiObjectData; struct _CkCapiSession; +typedef struct _CkCapiSlot CkCapiSlot; typedef struct _CkCapiObject CkCapiObject; typedef struct _CkCapiObjectData CkCapiObjectData; typedef struct _CkCapiSession CkCapiSession; +/* ------------------------------------------------------------------ + * ckcapi-token.c + */ + +/* Debug print something about an object */ +#define DBGO(obj, msg) \ + ckcapi_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg)) + +/* A function to load data for an object */ +typedef CK_RV (*CkCapiLoadData)(CkCapiSession* sess, struct _CkCapiObject* obj, + CkCapiObjectData** objdata); + +/* A function to free some data */ +typedef void (*CkCapiRelease)(void* data); + +/* Object functions */ +typedef struct _CkCapiObjectVtable +{ + CkCapiLoadData load_data; + CkCapiRelease release; +} +CkCapiObjectVtable; + +/* Represents a object we've seen */ +struct _CkCapiObject +{ + CK_OBJECT_HANDLE id; + CK_SLOT_ID slot; + CK_SESSION_HANDLE session; + const CkCapiObjectVtable* obj_funcs; + void* unique_key; + size_t unique_len; +}; + +/* Register a new object, a handle will be assigned to obj->id */ +CK_RV ckcapi_token_register_object (CK_SLOT_ID slot, CkCapiObject* obj); + +/* Lookup an object for a given object handle */ +CkCapiObject* ckcapi_token_lookup_object (CK_SLOT_ID slot, CK_OBJECT_HANDLE obj); + +/* Clear all objects for all tokens. Only done when finalizing */ +void ckcapi_token_cleanup_all (void); + +/* Get the number of the maximum object handle currently in memory */ +CK_OBJECT_HANDLE ckcapi_token_get_max_handle (void); + +unsigned int ckcapi_token_get_count (void); + +CK_BBOOL ckcapi_token_is_valid (CK_SLOT_ID slot); + +const char* ckcapi_token_get_display_name (CK_SLOT_ID slot); + +const char* ckcapi_token_get_store_name (CK_SLOT_ID slot); + +#define CKCAPI_SLOT_CA 0x00000001 +#define CKCAPI_SLOT_TRUSTED 0x00000002 + +CK_ULONG ckcapi_token_get_flags (CK_SLOT_ID slot); /* ------------------------------------------------------------------ * ckcapi-object.c @@ -64,9 +124,6 @@ typedef struct _CkCapiSession CkCapiSession; /* A function to get an attribute from ObjectData */ typedef CK_RV (*CkCapiGetAttribute)(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr); -/* A function to free some data */ -typedef void (*CkCapiRelease)(void* data); - /* Object data functions */ typedef struct _CkCapiObjectDataVtable { @@ -100,45 +157,10 @@ 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); -/* A function to load data for an object */ -typedef CK_RV (*CkCapiLoadData)(CkCapiSession* sess, struct _CkCapiObject* obj, - CkCapiObjectData** objdata); - -/* Object functions */ -typedef struct _CkCapiObjectVtable -{ - CkCapiLoadData load_data; - CkCapiRelease release; -} -CkCapiObjectVtable; - -/* Represents a object we've seen */ -struct _CkCapiObject -{ - CK_OBJECT_HANDLE id; - const CkCapiObjectVtable* obj_funcs; - void* unique_key; - size_t unique_len; -}; - -/* Debug print something about an object */ -#define DBGO(obj, msg) \ - ckcapi_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg)) +/* Debug print something about an object data */ #define DBGOD(objdata, msg) \ ckcapi_debug("O%d: %s", (objdata) ? (objdata)->obj : 0, (msg)) -/* Get the number of the maximum object handle currently in memory */ -CK_OBJECT_HANDLE ckcapi_object_get_max_handle (void); - -/* Lookup an object for a given object handle */ -CkCapiObject* ckcapi_object_lookup (CkCapiSession* sess, CK_OBJECT_HANDLE obj); - -/* Register a new object, a handle will be assigned to obj->id */ -CK_RV ckcapi_object_register (CkCapiSession* sess, CkCapiObject* obj); - -/* Clear all objects. Only done when finalizing */ -void ckcapi_object_clear_all (void); - /* * Each object has a unique key which guarantees that we're * not loading the same objects over and over again. @@ -184,9 +206,12 @@ typedef void (*CkCapiSessionCancel) (struct _CkCapiSession* sess); /* Represents an open session */ typedef struct _CkCapiSession { - CK_ULONG id; /* Unique ID for this session */ + CK_SESSION_HANDLE id; /* Unique ID for this session */ + CK_SLOT_ID slot; int in_call; /* Whether this session is use in PKCS#11 function */ + HCERTSTORE store; /* Handle to an open certificate store */ + int operation_type; /* Whether an operation is happening or not */ void* operation_data; /* Data for this operation */ CkCapiSessionCancel operation_cancel; /* Callback to cancel operation when necessary */ @@ -206,7 +231,7 @@ CkCapiSession; ckcapi_debug("S%d: %s", (sess) ? (sess)->id : 0, (msg)) /* Create a session */ -CkCapiSession* ckcapi_session_create (void); +CK_RV ckcapi_session_create (CK_SLOT_ID slot, CkCapiSession** ret); /* Destroy a session */ void ckcapi_session_destroy (CkCapiSession* sess); @@ -221,8 +246,8 @@ CK_RV ckcapi_session_get_lock_ref (CK_ULONG id, int remove, /* Unlock and unreference a session */ void ckcapi_session_unref_unlock (CkCapiSession* sess); -/* Close all sessions */ -void ckcapi_session_close_all (void); +/* Close all sessions on a certain slot/token */ +CK_RV ckcapi_session_close_all (CK_SLOT_ID slot); @@ -271,7 +296,7 @@ void ckcapi_session_enum_object_data (CkCapiSession* sess, CkCapiEnumObjectData enum_func, void* arg); - +void ckcapi_session_cleanup_all (void); /* ------------------------------------------------------------------- * ckcapi-cert.c -- cgit v1.2.3