[gnome-keyring: 4/10] [gck] Add support for transient PKCS#11 objects.



commit 4508771f734590140051391b0a9222451f2aa453
Author: Stef Walter <stef memberwebs com>
Date:   Sat Jul 18 22:42:48 2009 +0000

    [gck] Add support for transient PKCS#11 objects.
    
    Transient objects are not stored permanently. These may be token
    objects with token 'scope' but dissappear automatically at some
    point in the future.
    
    Auto-destructed objects are always token objects.

 pkcs11/gck/gck-module.c             |  114 +++++++++++++++-
 pkcs11/gck/gck-object.c             |  132 +++++++++++-------
 pkcs11/gck/gck-object.h             |   13 +-
 pkcs11/gck/gck-session.c            |   17 ++-
 pkcs11/gck/tests/Makefile.am        |    1 +
 pkcs11/gck/tests/unit-test-object.c |  262 +++++++++++++++++++++++++++++++++++
 pkcs11/gck/tests/unit-test-timer.c  |    2 +-
 pkcs11/pkcs11g.h                    |    2 +
 8 files changed, 478 insertions(+), 65 deletions(-)
---
diff --git a/pkcs11/gck/gck-module.c b/pkcs11/gck/gck-module.c
index 32cdcf3..f49fdac 100644
--- a/pkcs11/gck/gck-module.c
+++ b/pkcs11/gck/gck-module.c
@@ -29,10 +29,12 @@
 #include "gck-certificate.h"
 #include "gck-factory.h"
 #include "gck-manager.h"
+#include "gck-memory-store.h"
 #include "gck-module.h"
 #include "gck-private-key.h"
 #include "gck-public-key.h"
 #include "gck-session.h"
+#include "gck-store.h"
 #include "gck-timer.h"
 #include "gck-transaction.h"
 #include "gck-util.h"
@@ -46,13 +48,17 @@ enum {
 };
 
 struct _GckModulePrivate {
+	GMutex *mutex;                          /* The mutex controlling entry to this module */
+
 	GckManager *token_manager; 
 	GHashTable *virtual_slots_by_id;        /* Various slot partitions by their ID */
 	GHashTable *sessions_by_handle;         /* Mapping of handle to all open sessions */
 	gint handle_counter;                    /* Constantly incrementing counter for handles and the like */
 	GArray *factories;                      /* Various registered object factories */
 	gboolean factories_sorted;              /* Whether we need to sort the object factories */
-	GMutex *mutex;                          /* The mutex controlling entry to this module */
+
+	GHashTable *transient_objects;          /* Token objects that are not stored permanently. */
+	GckStore *transient_store;              /* Store for trantsient objects. */
 };
 
 typedef struct _VirtualSlot {
@@ -134,6 +140,10 @@ static const MechanismAndInfo mechanism_list[] = {
 /* Hidden function that you should not use */
 GMutex* _gck_module_get_scary_mutex_that_you_should_not_touch (GckModule *self);
 
+static void  remove_transient_object (GckModule *self, GckTransaction *transaction, GckObject *object);
+
+static void  add_transient_object    (GckModule *self, GckTransaction *transaction, GckObject *object);
+
 /* -----------------------------------------------------------------------------
  * INTERNAL 
  */
@@ -340,6 +350,76 @@ done:
 	g_free (dup);
 }
 
+
+static gboolean
+complete_transient_remove (GckTransaction *transaction, GckModule *self, GckObject *object)
+{
+	if (gck_transaction_get_failed (transaction))
+		add_transient_object (self, NULL, object);
+	g_object_unref (object);
+	return TRUE;
+}
+
+static void
+remove_transient_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+	g_assert (GCK_IS_MODULE (self));
+	g_assert (GCK_IS_OBJECT (object));
+
+	g_object_ref (object);
+
+	gck_manager_unregister_object (self->pv->token_manager, object);
+	if (!g_hash_table_remove (self->pv->transient_objects, object))
+		g_return_if_reached ();
+	g_object_set (object, "store", NULL, NULL);
+
+	if (transaction) {
+		gck_transaction_add (transaction, self,
+		                     (GckTransactionFunc)complete_transient_remove, 
+		                     g_object_ref (object));
+	}
+
+	g_object_unref (object);
+}
+
+static gboolean
+complete_transient_add (GckTransaction *transaction, GckModule *self, GckObject *object)
+{
+	if (gck_transaction_get_failed (transaction))
+		remove_transient_object (self, NULL, object);
+	g_object_unref (object);
+	return TRUE;
+}
+
+static void
+add_transient_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+	g_assert (GCK_IS_MODULE (self));
+	g_assert (GCK_IS_OBJECT (object));
+
+	/* Must not already be associated with a session or manager */
+	g_return_if_fail (gck_object_get_manager (object) == NULL);
+	g_return_if_fail (g_hash_table_lookup (self->pv->transient_objects, object) == NULL);
+
+	g_hash_table_insert (self->pv->transient_objects, object, g_object_ref (object));
+	gck_manager_register_object (self->pv->token_manager, object);
+	g_object_set (object, "store", self->pv->transient_store, NULL);
+
+	if (transaction) {
+		gck_transaction_add (transaction, self,
+		                     (GckTransactionFunc)complete_transient_add, 
+		                     g_object_ref (object));
+	}
+}
+
+static void
+dispose_unref_object (gpointer obj)
+{
+	g_assert (G_IS_OBJECT (obj));
+	g_object_run_dispose (obj);
+	g_object_unref (obj);
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT 
  */
@@ -431,10 +511,16 @@ static GObject*
 gck_module_constructor (GType type, guint n_props, GObjectConstructParam *props) 
 {
 	GckModule *self = GCK_MODULE (G_OBJECT_CLASS (gck_module_parent_class)->constructor(type, n_props, props));
+	CK_ATTRIBUTE attr;
+
 	g_return_val_if_fail (self, NULL);	
 
+	/* Register store attributes */
+	attr.type = CKA_LABEL;
+	attr.pValue = "";
+	attr.ulValueLen = 0;
+	gck_store_register_schema (self->pv->transient_store, &attr, NULL, 0);
 
-	
 	return G_OBJECT (self);
 }
 
@@ -453,6 +539,10 @@ gck_module_init (GckModule *self)
 	
 	g_atomic_int_set (&(self->pv->handle_counter), 1);
 	
+	/* Create the store for transient objects */
+	self->pv->transient_store = GCK_STORE (gck_memory_store_new ());
+	self->pv->transient_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, dispose_unref_object);
+
 	/* Register session object factories */
 	gck_module_register_factory (self, GCK_FACTORY_PRIVATE_KEY);
 	gck_module_register_factory (self, GCK_FACTORY_CERTIFICATE);
@@ -464,6 +554,8 @@ gck_module_dispose (GObject *obj)
 {
 	GckModule *self = GCK_MODULE (obj);
 
+	g_hash_table_remove_all (self->pv->transient_objects);
+
 	if (self->pv->token_manager)
 		g_object_unref (self->pv->token_manager);
 	self->pv->token_manager = NULL;
@@ -480,7 +572,13 @@ static void
 gck_module_finalize (GObject *obj)
 {
 	GckModule *self = GCK_MODULE (obj);
+
+	g_hash_table_destroy (self->pv->transient_objects);
+	self->pv->transient_objects = NULL;
 	
+	g_object_unref (self->pv->transient_store);
+	self->pv->transient_store = NULL;
+
 	g_assert (self->pv->token_manager == NULL);
 
 	g_assert (g_hash_table_size (self->pv->virtual_slots_by_id) == 0);
@@ -691,7 +789,11 @@ gck_module_store_token_object (GckModule *self, GckTransaction *transaction, Gck
 	g_return_if_fail (GCK_IS_MODULE (self));
 	g_return_if_fail (GCK_IS_OBJECT (object));
 	g_assert (GCK_MODULE_GET_CLASS (self)->store_token_object);
-	GCK_MODULE_GET_CLASS (self)->store_token_object (self, transaction, object);
+
+	if (gck_object_get_transient (object))
+		add_transient_object (self, transaction, object);
+	else
+		GCK_MODULE_GET_CLASS (self)->store_token_object (self, transaction, object);
 }
 
 void
@@ -700,7 +802,11 @@ gck_module_remove_token_object (GckModule *self, GckTransaction *transaction, Gc
 	g_return_if_fail (GCK_IS_MODULE (self));
 	g_return_if_fail (GCK_IS_OBJECT (object));
 	g_assert (GCK_MODULE_GET_CLASS (self)->remove_token_object);
-	GCK_MODULE_GET_CLASS (self)->remove_token_object (self, transaction, object);
+
+	if (gck_object_get_transient (object))
+		remove_transient_object (self, transaction, object);
+	else
+		GCK_MODULE_GET_CLASS (self)->remove_token_object (self, transaction, object);
 }
 
 void
diff --git a/pkcs11/gck/gck-object.c b/pkcs11/gck/gck-object.c
index 59e156f..a210b53 100644
--- a/pkcs11/gck/gck-object.c
+++ b/pkcs11/gck/gck-object.c
@@ -49,10 +49,10 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-typedef struct _GckObjectLifetime {
+typedef struct _GckObjectTransient {
 	GckTimer *timed_timer;
 	glong timed_when;
-} GckObjectLifetime;
+} GckObjectTransient;
 
 struct _GckObjectPrivate {
 	CK_OBJECT_HANDLE handle;
@@ -60,7 +60,7 @@ struct _GckObjectPrivate {
 	GckManager *manager;
 	GckStore *store;
 	gchar *unique;
-	GckObjectLifetime *lifetime;
+	GckObjectTransient *transient;
 };
 
 G_DEFINE_TYPE (GckObject, gck_object, G_TYPE_OBJECT);
@@ -74,16 +74,16 @@ kaboom_callback (GckTimer *timer, gpointer user_data)
 {
 	GckObject *self = user_data;
 	GckTransaction *transaction;
-	GckObjectLifetime *lifetime;
+	GckObjectTransient *transient;
 	GckSession *session;
 	CK_RV rv;
 
 	g_return_if_fail (GCK_IS_OBJECT (self));
-	g_return_if_fail (self->pv->lifetime);
-	lifetime = self->pv->lifetime;
+	g_return_if_fail (self->pv->transient);
+	transient = self->pv->transient;
 
-	g_return_if_fail (timer == lifetime->timed_timer);
-	lifetime->timed_timer = NULL;
+	g_return_if_fail (timer == transient->timed_timer);
+	transient->timed_timer = NULL;
 
 	g_object_ref (self);
 
@@ -108,17 +108,15 @@ static gboolean
 start_callback (GckTransaction *transaction, GObject *obj, gpointer user_data)
 {
 	GckObject *self = GCK_OBJECT (obj);
-	GckObjectLifetime *lifetime;
-	GckSession *session = user_data;
+	GckObjectTransient *transient;
 
 	g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE);
-	g_return_val_if_fail (GCK_IS_SESSION (session), FALSE);
-	g_return_val_if_fail (self->pv->lifetime, FALSE);
-	lifetime = self->pv->lifetime;
+	g_return_val_if_fail (self->pv->transient, FALSE);
+	transient = self->pv->transient;
 
-	g_return_val_if_fail (!lifetime->timed_timer, FALSE);
-	lifetime->timed_timer = gck_timer_start (gck_session_get_module (session), 
-	                                         lifetime->timed_when, kaboom_callback, self);
+	g_return_val_if_fail (!transient->timed_timer, FALSE);
+	transient->timed_timer = gck_timer_start (self->pv->module, transient->timed_when, 
+	                                          kaboom_callback, self);
 
 	return TRUE;
 }
@@ -158,9 +156,11 @@ gck_object_real_get_attribute (GckObject *self, CK_ATTRIBUTE* attr)
 		if (self->pv->unique)
 			return gck_attribute_set_string (attr, self->pv->unique);
 		return CKR_ATTRIBUTE_TYPE_INVALID;
+	case CKA_GNOME_TRANSIENT:
+		return gck_attribute_set_bool (attr, self->pv->transient ? TRUE : FALSE);
 	case CKA_GNOME_AUTO_DESTRUCT:
-		return gck_attribute_set_time (attr, self->pv->lifetime ?
-		                                     self->pv->lifetime->timed_when : -1);
+		return gck_attribute_set_time (attr, self->pv->transient ?
+		                                     self->pv->transient->timed_when : -1);
 	};
 
 	/* Give store a shot */
@@ -213,26 +213,54 @@ gck_object_real_set_attribute (GckObject *self, GckTransaction* transaction, CK_
 }
 
 static void
-gck_object_real_create_attribute (GckObject *self, GckTransaction *transaction, 
-	                          CK_ATTRIBUTE *attr, GckSession *session)
+gck_object_real_create_attributes (GckObject *self, GckTransaction *transaction, 
+                                   GckSession *session, CK_ATTRIBUTE *attrs, CK_ULONG n_attrs)
 {
+	CK_ATTRIBUTE_PTR transient_attr;
+	CK_ATTRIBUTE_PTR lifetime_attr;
+	gboolean transient = FALSE;
+	glong lifetime = -1;
 	CK_RV rv;
 
-	switch (attr->type) {
-	case CKA_GNOME_AUTO_DESTRUCT:
-		if (!self->pv->lifetime)
-			self->pv->lifetime = g_slice_new0 (GckObjectLifetime);
-		rv = gck_attribute_get_time (attr, &self->pv->lifetime->timed_when);
-		gck_attribute_consume (attr);
-		if (rv == CKR_OK) {
-			/* Must be a session object for an auto destruct */
-			if (self->pv->lifetime->timed_when >= 0)
-				gck_transaction_add (transaction, self, start_callback, session);
+	/* Parse the transient attribute */
+	transient_attr = gck_attributes_find (attrs, n_attrs, CKA_GNOME_TRANSIENT);
+	if (transient_attr) {
+		rv = gck_attribute_get_bool (transient_attr, &transient);
+		gck_attribute_consume (transient_attr);
+		if (rv != CKR_OK) {
+			gck_transaction_fail (transaction, rv);
+			return;
 		}
-		if (rv != CKR_OK)
+	}
+
+	/* Parse the auto destruct attribute */
+	lifetime_attr = gck_attributes_find (attrs, n_attrs, CKA_GNOME_AUTO_DESTRUCT);
+	if (lifetime_attr) {
+		rv = gck_attribute_get_time (lifetime_attr, &lifetime);
+		gck_attribute_consume (lifetime_attr);
+		if (rv != CKR_OK) {
 			gck_transaction_fail (transaction, rv);
-		return;
-	};
+			return;
+		}
+		
+		/* Default for the transient attribute */
+		if (!transient_attr)
+			transient = TRUE;
+	}
+
+	if (transient) {
+		self->pv->transient = g_slice_new0 (GckObjectTransient);
+		self->pv->transient->timed_when = lifetime;
+	}
+
+	if (lifetime >= 0) {
+		if (!self->pv->transient) {
+			gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+			return;
+		}
+
+		gck_transaction_add (transaction, self, start_callback, NULL);
+	}
 }
 
 static CK_RV
@@ -273,7 +301,7 @@ static void
 gck_object_dispose (GObject *obj)
 {
 	GckObject *self = GCK_OBJECT (obj);
-	GckObjectLifetime *lifetime;
+	GckObjectTransient *transient;
 	
 	if (self->pv->manager)
 		gck_manager_unregister_object (self->pv->manager, self);
@@ -282,14 +310,14 @@ gck_object_dispose (GObject *obj)
 	g_object_set (self, "store", NULL, NULL);
 	g_assert (self->pv->store == NULL);
 
-	if (self->pv->lifetime) {
-		lifetime = self->pv->lifetime;
-		if (lifetime->timed_timer)
-			gck_timer_cancel (lifetime->timed_timer);
-		lifetime->timed_timer = NULL;
+	if (self->pv->transient) {
+		transient = self->pv->transient;
+		if (transient->timed_timer)
+			gck_timer_cancel (transient->timed_timer);
+		transient->timed_timer = NULL;
 
-		g_slice_free (GckObjectLifetime, lifetime);
-		self->pv->lifetime = NULL;
+		g_slice_free (GckObjectTransient, transient);
+		self->pv->transient = NULL;
 	}
     
 	G_OBJECT_CLASS (gck_object_parent_class)->dispose (obj);
@@ -307,7 +335,7 @@ gck_object_finalize (GObject *obj)
 	g_object_weak_unref (G_OBJECT (self->pv->module), module_went_away, self);
 	self->pv->module = NULL;
 
-	g_assert (self->pv->lifetime == NULL);
+	g_assert (self->pv->transient == NULL);
 
 	G_OBJECT_CLASS (gck_object_parent_class)->finalize (obj);
 }
@@ -414,7 +442,7 @@ gck_object_class_init (GckObjectClass *klass)
 	klass->unlock = gck_object_real_unlock;
 	klass->get_attribute = gck_object_real_get_attribute;
 	klass->set_attribute = gck_object_real_set_attribute;
-	klass->create_attribute = gck_object_real_create_attribute;
+	klass->create_attributes = gck_object_real_create_attributes;
 	
 	g_object_class_install_property (gobject_class, PROP_HANDLE,
 	           g_param_spec_ulong ("handle", "Handle", "Object handle",
@@ -485,19 +513,19 @@ gck_object_set_attribute (GckObject *self, GckTransaction *transaction,
 }
 
 void
-gck_object_create_attribute (GckObject *self, GckTransaction *transaction,
-                             CK_ATTRIBUTE_PTR attr, GckSession *session)
+gck_object_create_attributes (GckObject *self, GckTransaction *transaction, GckSession *session,
+                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	g_return_if_fail (GCK_IS_OBJECT (self));
 	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
 	g_return_if_fail (!gck_transaction_get_failed (transaction));
 	g_return_if_fail (GCK_IS_SESSION (session));
-	g_return_if_fail (attr);
+	g_return_if_fail (attrs);
 
-	g_assert (GCK_OBJECT_GET_CLASS (self)->create_attribute);
+	g_assert (GCK_OBJECT_GET_CLASS (self)->create_attributes);
 
 	/* Check that the value will actually change */
-	GCK_OBJECT_GET_CLASS (self)->create_attribute (self, transaction, attr, session);
+	GCK_OBJECT_GET_CLASS (self)->create_attributes (self, transaction, session, attrs, n_attrs);
 }
 
 void
@@ -589,6 +617,14 @@ gck_object_get_unique (GckObject *self)
 	return self->pv->unique;
 }
 
+gboolean
+gck_object_get_transient (GckObject *self)
+{
+	g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE);
+	return self->pv->transient ? TRUE : FALSE;
+}
+
+
 CK_RV
 gck_object_unlock (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
 {
diff --git a/pkcs11/gck/gck-object.h b/pkcs11/gck/gck-object.h
index 0a3b065..44d79b8 100644
--- a/pkcs11/gck/gck-object.h
+++ b/pkcs11/gck/gck-object.h
@@ -56,8 +56,8 @@ struct _GckObjectClass {
 	
 	void (*set_attribute) (GckObject *object, GckTransaction *transaction, CK_ATTRIBUTE *attr);
 	
-	void (*create_attribute) (GckObject *object, GckTransaction *transaction, 
-	                          CK_ATTRIBUTE *attr, GckSession *session);
+	void (*create_attributes) (GckObject *object, GckTransaction *transaction, GckSession *session,
+	                           CK_ATTRIBUTE *attrs, CK_ULONG n_attrs);
 
 	CK_RV (*unlock) (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
 };
@@ -75,6 +75,8 @@ GckManager*            gck_object_get_manager            (GckObject *self);
 
 const gchar*           gck_object_get_unique             (GckObject *self);
 
+gboolean               gck_object_get_transient          (GckObject *self);
+
 CK_RV                  gck_object_unlock                 (GckObject *self, 
                                                           CK_UTF8CHAR_PTR pin, 
                                                           CK_ULONG n_pin);
@@ -93,10 +95,11 @@ void                   gck_object_set_attribute          (GckObject *self,
                                                           GckTransaction *transaction,
                                                           CK_ATTRIBUTE_PTR attr);
 
-void                   gck_object_create_attribute       (GckObject *self,
+void                   gck_object_create_attributes      (GckObject *self,
                                                           GckTransaction *transaction,
-                                                          CK_ATTRIBUTE_PTR attr,
-                                                          GckSession *session);
+                                                          GckSession *session,
+                                                          CK_ATTRIBUTE_PTR attrs,
+                                                          CK_ULONG n_attrs);
 
 void                   gck_object_notify_attribute       (GckObject *self,
                                                           CK_ATTRIBUTE_TYPE attr_type);
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index 334a770..dd4e70a 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -269,8 +269,9 @@ lookup_object_from_handle (GckSession *self, CK_OBJECT_HANDLE handle,
 	 */
 	if (writable) {
 		if (is_token) {
-			if (gck_module_get_write_protected (self->pv->module))
-				return CKR_TOKEN_WRITE_PROTECTED;
+			if (!gck_object_get_transient (object))
+				if (gck_module_get_write_protected (self->pv->module))
+					return CKR_TOKEN_WRITE_PROTECTED;
 			if (self->pv->read_only)
 				return CKR_SESSION_READ_ONLY;
 		}
@@ -740,6 +741,7 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
 	CK_ULONG n_attrs, i;
 	GckFactory factory;
 	gboolean is_token;
+	gboolean is_transient;
 	gboolean is_private;
 	CK_RV rv;
 
@@ -756,11 +758,13 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
 	
 	/* Find out where we'll be creating this */
 	if (!gck_attributes_find_boolean (template, count, CKA_TOKEN, &is_token))
-		is_token = CK_FALSE;
+		is_token = FALSE;
+	if (!gck_attributes_find_boolean (template, count, CKA_GNOME_TRANSIENT, &is_transient))
+		is_transient = FALSE;
 		
 	/* See if we can create due to read-only */
 	if (is_token) {
-		if (gck_module_get_write_protected (self->pv->module))
+		if (!is_transient && gck_module_get_write_protected (self->pv->module))
 			return CKR_TOKEN_WRITE_PROTECTED;
 		if (self->pv->read_only)
 			return CKR_SESSION_READ_ONLY;
@@ -792,9 +796,8 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
 	}
 	
 	/* Give the object a chance to create additional attributes */
-	for (i = 0; i < n_attrs && !gck_transaction_get_failed (transaction); ++i) {
-		if (!gck_attribute_consumed (&attrs[i]))
-			gck_object_create_attribute (object, transaction, &attrs[i], self);
+	if (!gck_transaction_get_failed (transaction)) {
+		gck_object_create_attributes (object, transaction, self, attrs, n_attrs);
 	}
 
 	/* Find somewhere to store the object */
diff --git a/pkcs11/gck/tests/Makefile.am b/pkcs11/gck/tests/Makefile.am
index e1b72e8..4bd2b10 100644
--- a/pkcs11/gck/tests/Makefile.am
+++ b/pkcs11/gck/tests/Makefile.am
@@ -11,6 +11,7 @@ UNIT_AUTO = \
 	unit-test-crypto.c \
 	unit-test-data-asn1.c \
 	unit-test-data-der.c \
+	unit-test-object.c \
 	unit-test-timer.c \
 	unit-test-transaction.c \
 	unit-test-store.c \
diff --git a/pkcs11/gck/tests/unit-test-object.c b/pkcs11/gck/tests/unit-test-object.c
new file mode 100644
index 0000000..d55f36d
--- /dev/null
+++ b/pkcs11/gck/tests/unit-test-object.c
@@ -0,0 +1,262 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-timer.c: Test thread timer functionality
+
+   Copyright (C) 2009 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "run-auto-test.h"
+#include "test-module.h"
+
+#include "gck/gck-attributes.h"
+#include "gck/gck-object.h"
+#include "gck/gck-session.h"
+#include "gck/gck-module.h"
+
+#include "pkcs11g.h"
+
+static GckModule *module = NULL;
+static GckSession *session = NULL;
+static guchar *certificate_data = NULL;
+static gsize certificate_n_data = 0;
+
+DEFINE_SETUP(object_setup)
+{
+	CK_SESSION_HANDLE handle;
+	CK_RV rv;
+	
+	module = test_module_initialize ();
+	test_module_enter ();
+	
+	rv = gck_module_C_OpenSession (module, 1, CKF_SERIAL_SESSION | CKF_RW_SESSION, 
+	                               NULL, NULL, &handle);
+	g_assert (rv == CKR_OK);
+	
+	session = gck_module_lookup_session (module, handle);
+	g_assert (session);
+	
+	certificate_data = test_read_testdata ("test-certificate-1.der", &certificate_n_data);
+}
+
+DEFINE_TEARDOWN(object_teardown)
+{
+	CK_RV rv;
+	
+	g_free (certificate_data);
+	certificate_data = NULL;
+	certificate_n_data = 0;
+	
+	rv = gck_module_C_CloseAllSessions (module, 1);
+	g_assert (rv == CKR_OK);
+	
+	test_module_leave ();
+	test_module_finalize ();
+	module = NULL;
+	session = NULL;
+}
+
+static gboolean
+check_object_exists (CK_OBJECT_HANDLE handle)
+{
+	CK_BBOOL token;
+	CK_ATTRIBUTE attr = { CKA_TOKEN, &token, sizeof (token) };
+	CK_RV rv;
+	
+	rv = gck_session_C_GetAttributeValue (session, handle, &attr, 1);
+	if (rv == CKR_OBJECT_HANDLE_INVALID)
+		return FALSE;
+	
+	g_assert (rv == CKR_OK);
+	return TRUE;
+}
+
+DEFINE_TEST(object_create_destroy_transient)
+{
+	CK_BBOOL transient = CK_TRUE;
+	CK_BBOOL token = CK_TRUE;
+	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	
+	CK_ATTRIBUTE attrs[] = {
+	        { CKA_TOKEN, &token, sizeof (token) },
+		{ CKA_GNOME_TRANSIENT, &transient, sizeof (transient) },
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+		{ CKA_VALUE, certificate_data, certificate_n_data },
+	};
+	
+	CK_ATTRIBUTE lookup = { CKA_GNOME_TRANSIENT, &transient, sizeof (transient) };
+	CK_OBJECT_HANDLE handle;
+	CK_RV rv;
+	
+	rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+	g_assert (rv == CKR_OK);
+	g_assert (handle != 0);
+	
+	g_assert (check_object_exists (handle));
+	
+	transient = CK_FALSE;
+	rv = gck_session_C_GetAttributeValue (session, handle, &lookup, 1);
+	g_assert (rv == CKR_OK);
+	g_assert (transient == CK_TRUE);
+	
+	rv = gck_session_C_DestroyObject (session, handle);
+	g_assert (rv == CKR_OK);
+	
+	g_assert (!check_object_exists (handle));
+}
+
+DEFINE_TEST(object_transient_transacted_fail)
+{
+	CK_BBOOL transient = CK_TRUE;
+	CK_BBOOL token = CK_TRUE;
+	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	CK_ULONG invalid = 4;
+	
+	CK_ATTRIBUTE attrs[] = {
+	        { CKA_TOKEN, &token, sizeof (token) },
+		{ CKA_GNOME_TRANSIENT, &transient, sizeof (transient) },
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+		{ CKA_VALUE, certificate_data, certificate_n_data },
+		
+		/* An invalid attribute, should cause transaction to fail */
+		{ CKA_BITS_PER_PIXEL, &invalid, sizeof (invalid) }  
+	};
+	
+	CK_OBJECT_HANDLE handle;
+	CK_RV rv;
+	
+	rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+	g_assert (rv == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(object_create_transient_bad_value)
+{
+	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	
+	CK_ATTRIBUTE attrs[] = {
+		{ CKA_GNOME_TRANSIENT, NULL, 0 },
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+		{ CKA_VALUE, certificate_data, certificate_n_data },
+	};
+
+	CK_OBJECT_HANDLE handle;
+	CK_RV rv;
+	
+	/* Can't have a non-transient object that auto-destructs */
+	rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+	g_assert (rv == CKR_ATTRIBUTE_VALUE_INVALID);
+}
+
+DEFINE_TEST(object_create_auto_destruct)
+{
+	CK_BBOOL token = CK_FALSE;
+	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	gchar lifetime[16];
+	gchar check[16];
+	
+	CK_ATTRIBUTE attrs[] = {
+       		{ CKA_GNOME_AUTO_DESTRUCT, lifetime, sizeof (lifetime) },
+	        { CKA_TOKEN, &token, sizeof (token) },
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+		{ CKA_VALUE, certificate_data, certificate_n_data },
+	};
+	
+	CK_BBOOL transient;
+	
+	CK_ATTRIBUTE lookups[] = { 
+		{ CKA_GNOME_AUTO_DESTRUCT, check, sizeof (check) },
+		{ CKA_GNOME_TRANSIENT, &transient, sizeof (transient) }
+	};
+	
+	CK_OBJECT_HANDLE handle;
+	GTimeVal tv;
+	CK_RV rv;
+	
+	/* Fill in the special attribute */
+	g_get_current_time (&tv);
+	rv = gck_attribute_set_time (&attrs[0], tv.tv_sec + 2);
+	g_assert (rv == CKR_OK);
+	
+	rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+	g_assert (rv == CKR_OK);
+	g_assert (handle != 0);
+	
+	g_assert (check_object_exists (handle));
+	
+	transient = CK_FALSE;
+	rv = gck_session_C_GetAttributeValue (session, handle, lookups, G_N_ELEMENTS (lookups));
+	g_assert (rv == CKR_OK);
+	g_assert (transient == TRUE);
+	g_assert (memcmp (lifetime, check, 16) == 0);
+	
+	test_module_leave ();
+	test_mainloop_run (2200);
+	test_module_enter ();
+	
+	g_assert (!check_object_exists (handle));
+}
+
+DEFINE_TEST(object_create_auto_destruct_not_transient)
+{
+	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	CK_BBOOL transient = CK_FALSE; 
+	
+	CK_ATTRIBUTE attrs[] = {
+       		{ CKA_GNOME_AUTO_DESTRUCT, "1999010101010100", 16 },
+		{ CKA_GNOME_TRANSIENT, &transient, sizeof (transient) },
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+		{ CKA_VALUE, certificate_data, certificate_n_data },
+	};
+
+	CK_OBJECT_HANDLE handle;
+	CK_RV rv;
+	
+	/* Can't have a non-transient object that auto-destructs */
+	rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+	g_assert (rv == CKR_TEMPLATE_INCONSISTENT);
+}
+
+DEFINE_TEST(object_create_auto_destruct_bad_value)
+{
+	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	
+	CK_ATTRIBUTE attrs[] = {
+       		{ CKA_GNOME_AUTO_DESTRUCT, "1999", 4 },
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+		{ CKA_VALUE, certificate_data, certificate_n_data },
+	};
+
+	CK_OBJECT_HANDLE handle;
+	CK_RV rv;
+	
+	/* Can't have a non-transient object that auto-destructs */
+	rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+	g_assert (rv == CKR_ATTRIBUTE_VALUE_INVALID);
+}
diff --git a/pkcs11/gck/tests/unit-test-timer.c b/pkcs11/gck/tests/unit-test-timer.c
index e826799..d463041 100644
--- a/pkcs11/gck/tests/unit-test-timer.c
+++ b/pkcs11/gck/tests/unit-test-timer.c
@@ -26,7 +26,7 @@
 
 #include "gck/gck-timer.h"
 
-GckModule *module = NULL;
+static GckModule *module = NULL;
 
 DEFINE_SETUP(timer_setup)
 {
diff --git a/pkcs11/pkcs11g.h b/pkcs11/pkcs11g.h
index d2ac6d9..da84c40 100644
--- a/pkcs11/pkcs11g.h
+++ b/pkcs11/pkcs11g.h
@@ -103,4 +103,6 @@
 
 #define CKA_GNOME_AUTO_DESTRUCT                  (CKO_GNOME + 200)
 
+#define CKA_GNOME_TRANSIENT                      (CKO_GNOME + 201)
+
 #endif /* PKCS11G_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]