summaryrefslogtreecommitdiff
path: root/p11-capi-token.c
diff options
context:
space:
mode:
Diffstat (limited to 'p11-capi-token.c')
-rw-r--r--p11-capi-token.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/p11-capi-token.c b/p11-capi-token.c
new file mode 100644
index 0000000..13a87d6
--- /dev/null
+++ b/p11-capi-token.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-object.h"
+#include "p11-capi-token.h"
+
+static P11cArray* object_array = NULL;
+static P11cHash* object_hash = NULL;
+static P11cArray* logged_in_slots = NULL;
+
+typedef struct _SlotInfo
+{
+ const char* capi_store;
+ const char* display_name;
+ CK_ULONG slot_flags;
+}
+SlotInfo;
+
+#define SLOT_OFFSET 0x00001000
+
+static SlotInfo slot_info[] = {
+ { "My", "Personal Certificates", P11c_SLOT_TRUSTED | P11c_SLOT_CERTS },
+ { "AddressBook", "Address Book Certificates", P11c_SLOT_CERTS },
+ { "CA", "Certificate Authorities", P11c_SLOT_CA | P11c_SLOT_CERTS },
+ { "Root", "Root Authorities", P11c_SLOT_TRUSTED | P11c_SLOT_CA | P11c_SLOT_CERTS },
+ { "Trust", "Trust", P11c_SLOT_CERTS },
+ { "TrustedPeople", "Trusted People", P11c_SLOT_TRUSTED | P11c_SLOT_CERTS },
+ { "AuthRoot", "Auth Root", P11c_SLOT_CERTS },
+ { NULL, "All User Keys", P11c_SLOT_ANYKEY }
+};
+
+#define SLOT_TO_OFFSET(slot) \
+ ((slot) & ~(SLOT_OFFSET))
+
+#define OFFSET_TO_SLOT(offset) \
+ ((offset) | SLOT_OFFSET)
+
+unsigned int
+p11c_token_get_count(void)
+{
+ return sizeof(slot_info) / sizeof(slot_info[0]);
+}
+
+CK_SLOT_ID
+p11c_token_get_slot_id(unsigned int offset)
+{
+ ASSERT(offset < p11c_token_get_count());
+ return OFFSET_TO_SLOT(offset);
+}
+
+CK_BBOOL
+p11c_token_is_valid(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ return offset >= 0 && offset < p11c_token_get_count();
+}
+
+const char*
+p11c_token_get_display_name(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ ASSERT(p11c_token_is_valid(slot));
+ ASSERT(slot_info[offset].display_name);
+ return slot_info[offset].display_name;
+}
+
+const char*
+p11c_token_get_store_name(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ ASSERT(p11c_token_is_valid(slot));
+ return slot_info[offset].capi_store;
+}
+
+CK_ULONG
+p11c_token_get_flags(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ ASSERT(p11c_token_is_valid(slot));
+ return slot_info[offset].slot_flags;
+}
+
+static void
+object_free(P11cObject* obj)
+{
+ ASSERT(obj);
+ ASSERT(obj->obj_funcs);
+ ASSERT(obj->obj_funcs->release);
+ (obj->obj_funcs->release)(obj);
+}
+
+void
+p11c_token_cleanup_all(void)
+{
+ size_t i;
+
+ p11c_lock_global();
+
+ if(object_hash)
+ {
+ p11c_hash_free(object_hash, NULL);
+ object_hash = NULL;
+ }
+
+ if(object_array)
+ {
+ for(i = 1; i < object_array->len; ++i)
+ {
+ ASSERT(p11c_array_index(object_array, P11cObject*, i));
+ object_free(p11c_array_index(object_array, P11cObject*, i));
+ }
+
+ p11c_array_free(object_array, TRUE);
+ object_array = NULL;
+ }
+
+ if(logged_in_slots)
+ {
+ p11c_array_free(logged_in_slots, TRUE);
+ logged_in_slots = NULL;
+ }
+
+ p11c_unlock_global();
+}
+
+CK_OBJECT_HANDLE
+p11c_token_get_max_handle(void)
+{
+ if(!object_array)
+ return 0;
+ return object_array->len;
+}
+
+P11cObject*
+p11c_token_lookup_object(CK_SLOT_ID slot, CK_OBJECT_HANDLE obj)
+{
+ /* This must be called without any locks held */
+
+ P11cObject* ret = NULL;
+
+ ASSERT(slot);
+ ASSERT(obj > 0);
+
+ p11c_lock_global();
+
+ if(object_array && obj < object_array->len)
+ ret = p11c_array_index(object_array, P11cObject*, obj);
+
+ p11c_unlock_global();
+
+ /* Must belong to the right slot */
+ if(ret && ret->slot != slot)
+ ret = NULL;
+
+ return ret;
+}
+
+static unsigned int
+object_hash_func(const void* a)
+{
+ P11cObject* obj = (P11cObject*)a;
+ unsigned int hash = p11c_hash_pointer(obj->obj_funcs);
+ hash ^= (obj->obj_funcs->hash_object)(obj);
+ return hash;
+}
+
+static int
+object_equal_func(const void* a, const void* b)
+{
+ P11cObject* ca = (P11cObject*)a;
+ P11cObject* cb = (P11cObject*)b;
+ if(ca == cb)
+ return 1;
+ if(ca->obj_funcs != cb->obj_funcs)
+ return 0;
+ return (ca->obj_funcs->equal_object)(ca, cb);
+}
+
+CK_RV
+p11c_token_register_object(CK_SLOT_ID slot, P11cObject* obj)
+{
+ P11cObject* prev;
+ CK_RV ret = CKR_OK;
+
+ ASSERT(slot);
+ ASSERT(obj->id == 0);
+
+ DBG(("registering object"));
+
+ p11c_lock_global();
+
+ if(!object_array)
+ {
+ object_array = p11c_array_sized_new(0, 1, sizeof(P11cObject*), 16);
+ if(object_array)
+ {
+ /* A blank entry for '0' */
+ P11cObject* blank = NULL;
+ p11c_array_append(object_array, blank);
+ }
+
+ object_hash = p11c_hash_new(object_hash_func, object_equal_func);
+
+ if(!object_array || !object_hash)
+ {
+ /* Allocation failed above */
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+
+ if(ret == CKR_OK)
+ {
+ ASSERT(object_array);
+ ASSERT(object_hash);
+
+ /* Look in the hash and find a previous object */
+ prev = p11c_hash_get(object_hash, obj);
+ if(prev)
+ {
+ /* Register it in the previous object's place */
+ obj->id = prev->id;
+ ASSERT(prev->id < object_array->len);
+ if(p11c_hash_set(object_hash, obj, obj))
+ {
+ p11c_array_index(object_array, P11cObject*, 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(p11c_hash_set(object_hash, obj, obj))
+ {
+ if(p11c_array_append(object_array, obj))
+ {
+ DBGO(obj, "registered new object id");
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+
+ /* Roll back our addition */
+ p11c_hash_rem(object_hash, obj);
+ }
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+ }
+
+ if(ret == CKR_OK)
+ obj->slot = slot;
+
+ p11c_unlock_global();
+
+ return ret;
+
+}
+
+CK_BBOOL
+p11c_token_is_logged_in(CK_SLOT_ID slot)
+{
+ unsigned int count, offset;
+
+ ASSERT(p11c_token_is_valid(slot));
+
+ if(!logged_in_slots)
+ return CK_FALSE;
+
+ offset = SLOT_TO_OFFSET(slot);
+ count = p11c_token_get_count();
+
+ ASSERT(logged_in_slots->len == count && offset < count);
+ return p11c_array_index(logged_in_slots, CK_BBOOL, offset);
+}
+
+CK_RV
+p11c_token_login(CK_SLOT_ID slot)
+{
+ unsigned int i, count;
+ unsigned int offset;
+ CK_BBOOL value;
+
+ ASSERT(p11c_token_is_valid(slot));
+
+ offset = SLOT_TO_OFFSET(slot);
+ count = p11c_token_get_count();
+
+ if(!logged_in_slots)
+ {
+ logged_in_slots = p11c_array_sized_new(0, 1, sizeof(CK_BBOOL), count);
+ if(!logged_in_slots)
+ return CKR_HOST_MEMORY;
+
+ value = CK_FALSE;
+ for(i = 0; i < count; ++i)
+ p11c_array_append(logged_in_slots, value);
+
+ }
+
+ ASSERT(logged_in_slots->len == count && offset < count);
+ if(p11c_array_index(logged_in_slots, CK_BBOOL, offset))
+ return CKR_USER_ALREADY_LOGGED_IN;
+
+ p11c_array_index(logged_in_slots, CK_BBOOL, offset) = CK_TRUE;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_token_logout(CK_SLOT_ID slot)
+{
+ unsigned int count, offset;
+
+ ASSERT(p11c_token_is_valid(slot));
+
+ if(!logged_in_slots)
+ return CKR_USER_NOT_LOGGED_IN;
+
+ offset = SLOT_TO_OFFSET(slot);
+ count = p11c_token_get_count();
+
+ ASSERT(logged_in_slots->len == count && offset < count);
+ if(!p11c_array_index(logged_in_slots, CK_BBOOL, offset))
+ return CKR_USER_NOT_LOGGED_IN;
+
+ p11c_array_index(logged_in_slots, CK_BBOOL, offset) = CK_FALSE;
+ return CKR_OK;
+}