[gnome-keyring] [pkcs11] Rework how credentials, and auto-destruct work.



commit d6192caf4dad9a6166c7c6e248f3fb159f1d5ee1
Author: Stef Walter <stef memberwebs com>
Date:   Sun Dec 20 17:19:38 2009 +0000

    [pkcs11] Rework how credentials, and auto-destruct work.
    
    Add the concept of a CKA_CREDENTIAL_TEMPLATE from which
    credential objects for a given object take attributes.
    
    Change around the various auto-destruct attributes.

 daemon/ssh-agent/gkd-ssh-agent-ops.c               |   18 +--
 pkcs11/gck/gck-attributes.c                        |   42 +++++
 pkcs11/gck/gck-attributes.h                        |    4 +
 pkcs11/gck/gck-credential.c                        |  188 +++++++++++++------
 pkcs11/gck/gck-credential.h                        |   21 ++-
 pkcs11/gck/gck-object.c                            |  152 ++++++++++++----
 pkcs11/gck/gck-object.h                            |    2 +
 pkcs11/gck/gck-private-xsa-key.c                   |   19 +--
 pkcs11/gck/gck-session.c                           |   59 +------
 pkcs11/gck/gck-session.h                           |   11 +-
 pkcs11/gck/gck-timer.c                             |    7 +-
 pkcs11/gck/gck-timer.h                             |    2 +-
 pkcs11/gck/tests/unit-test-credential.c            |   67 +++-----
 pkcs11/gck/tests/unit-test-object.c                |   51 ++----
 pkcs11/gck/tests/unit-test-timer.c                 |   47 ++---
 pkcs11/pkcs11g.h                                   |   15 --
 pkcs11/pkcs11i.h                                   |   22 +++
 pkcs11/secret-store/gck-secret-binary.c            |   17 +-
 pkcs11/secret-store/gck-secret-collection.c        |  107 ++++++++---
 pkcs11/secret-store/gck-secret-collection.h        |   10 +-
 pkcs11/secret-store/gck-secret-item.c              |   13 +-
 pkcs11/secret-store/gck-secret-textual.c           |    5 +-
 .../tests/unit-test-secret-collection.c            |   18 ++-
 23 files changed, 521 insertions(+), 376 deletions(-)
---
diff --git a/daemon/ssh-agent/gkd-ssh-agent-ops.c b/daemon/ssh-agent/gkd-ssh-agent-ops.c
index 98567ae..07ae493 100644
--- a/daemon/ssh-agent/gkd-ssh-agent-ops.c
+++ b/daemon/ssh-agent/gkd-ssh-agent-ops.c
@@ -28,6 +28,7 @@
 
 #include "pkcs11/pkcs11.h"
 #include "pkcs11/pkcs11g.h"
+#include "pkcs11/pkcs11i.h"
 
 #include "egg/egg-secure-memory.h"
 
@@ -545,12 +546,8 @@ static gboolean
 load_contraints (EggBuffer *buffer, gsize offset, gsize *next_offset,
                  GP11Attributes *priv, GP11Attributes *pub)
 {
-	GTimeVal tv;
 	guchar constraint;
 	guint32 lifetime;
-	time_t time;
-	struct tm tm;
-	gchar buf[20];
 
 	/*
 	 * Constraints are a byte flag, and optional data depending
@@ -566,17 +563,8 @@ load_contraints (EggBuffer *buffer, gsize offset, gsize *next_offset,
 			if (!egg_buffer_get_uint32 (buffer, offset, &offset, &lifetime))
 				return FALSE;
 
-			g_get_current_time (&tv);
-			time = tv.tv_sec + lifetime;
-
-			if (!gmtime_r (&time, &tm))
-				g_return_val_if_reached (FALSE);
-
-			if (!strftime(buf, sizeof (buf), "%Y%m%d%H%M%S00", &tm))
-				g_return_val_if_reached (FALSE);
-
-			gp11_attributes_add_data (pub, CKA_GNOME_AUTO_DESTRUCT, buf, 16);
-			gp11_attributes_add_data (priv, CKA_GNOME_AUTO_DESTRUCT, buf, 16);
+			gp11_attributes_add_ulong (pub, CKA_G_DESTRUCT_AFTER, lifetime);
+			gp11_attributes_add_ulong (priv, CKA_G_DESTRUCT_AFTER, lifetime);
 			break;
 
 		case GKD_SSH_FLAG_CONSTRAIN_CONFIRM:
diff --git a/pkcs11/gck/gck-attributes.c b/pkcs11/gck/gck-attributes.c
index f68babf..62465cd 100644
--- a/pkcs11/gck/gck-attributes.c
+++ b/pkcs11/gck/gck-attributes.c
@@ -287,6 +287,48 @@ gck_attribute_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
 	return CKR_OK;
 }
 
+CK_RV
+gck_attribute_set_template (CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_PTR template,
+                            CK_ULONG n_template)
+{
+	CK_ATTRIBUTE_PTR array;
+	CK_RV rv;
+	gulong len;
+	gulong i;
+
+	g_assert (attr);
+	g_warn_if_fail ((attr->type & CKF_ARRAY_ATTRIBUTE) != 0);
+
+	len = sizeof (CK_ATTRIBUTE) * n_template;
+	if (!attr->pValue) {
+		attr->ulValueLen = len;
+		return CKR_OK;
+	} else if (len > attr->ulValueLen) {
+		attr->ulValueLen = (CK_ULONG)-1;
+		return CKR_BUFFER_TOO_SMALL;
+	}
+
+	attr->ulValueLen = len;
+	array = attr->pValue;
+	rv = CKR_OK;
+
+	/* Start working with individual elements */
+	for (i = 0; i < n_template; ++i) {
+		array[i].type = template[i].type;
+		if (!array[i].pValue) {
+			array[i].ulValueLen = template[i].ulValueLen;
+		} else if (array[i].ulValueLen < template[i].ulValueLen) {
+			array[i].ulValueLen = (CK_ULONG)-1;
+			rv = CKR_BUFFER_TOO_SMALL;
+		} else {
+			memcpy(array[i].pValue, template[i].pValue, template[i].ulValueLen);
+			array[i].ulValueLen = template[i].ulValueLen;
+		}
+	}
+
+	return CKR_OK;
+}
+
 gboolean
 gck_attribute_equal (gconstpointer v1, gconstpointer v2)
 {
diff --git a/pkcs11/gck/gck-attributes.h b/pkcs11/gck/gck-attributes.h
index dc266bb..5e8bcb6 100644
--- a/pkcs11/gck/gck-attributes.h
+++ b/pkcs11/gck/gck-attributes.h
@@ -67,6 +67,10 @@ CK_RV                 gck_attribute_set_data                           (CK_ATTRI
 CK_RV                 gck_attribute_set_mpi                            (CK_ATTRIBUTE_PTR attr, 
                                                                         gcry_mpi_t mpi);
 
+CK_RV                 gck_attribute_set_template                       (CK_ATTRIBUTE_PTR attr,
+                                                                        CK_ATTRIBUTE_PTR template,
+                                                                        CK_ULONG n_template);
+
 guint                 gck_attribute_hash                               (gconstpointer v);
 
 gboolean              gck_attribute_equal                              (gconstpointer a,
diff --git a/pkcs11/gck/gck-credential.c b/pkcs11/gck/gck-credential.c
index d0e97ca..74ce3e6 100644
--- a/pkcs11/gck/gck-credential.c
+++ b/pkcs11/gck/gck-credential.c
@@ -28,13 +28,12 @@
 #include "gck-transaction.h"
 
 #include "pkcs11/pkcs11.h"
-#include "pkcs11/pkcs11g.h"
+#include "pkcs11/pkcs11i.h"
 
 enum {
 	PROP_0,
 	PROP_OBJECT,
-	PROP_SECRET,
-	PROP_USES_REMAINING
+	PROP_SECRET
 };
 
 struct _GckCredentialPrivate {
@@ -42,13 +41,12 @@ struct _GckCredentialPrivate {
 	/* The object we authenticated */
 	GckObject *object;
 
-	/* Optional secret and/or data */
+	/* Secret which created this credential */
 	GckSecret *secret;
-	gpointer user_data;
-	GDestroyNotify destroy;
 
-	/* Can limit by number of uses remaining */
-	gint uses_remaining;
+	/* Stored data */
+	GType user_type;
+	gpointer user_data;
 };
 
 G_DEFINE_TYPE (GckCredential, gck_credential, GCK_TYPE_OBJECT);
@@ -133,6 +131,21 @@ object_went_away (gpointer data, GObject *old_object)
 	self_destruct (self);
 }
 
+static void
+clear_data (GckCredential *self)
+{
+	if (!self->pv->user_data)
+		return;
+	if (G_TYPE_IS_BOXED (self->pv->user_type))
+		g_boxed_free (self->pv->user_type, self->pv->user_data);
+	else if (G_TYPE_IS_OBJECT (self->pv->user_type))
+		g_object_unref (self->pv->user_data);
+	else
+		g_assert_not_reached ();
+	self->pv->user_data = NULL;
+	self->pv->user_type = 0;
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -155,12 +168,6 @@ gck_credential_real_get_attribute (GckObject *base, GckSession *session, CK_ATTR
 		handle = self->pv->object ? gck_object_get_handle (self->pv->object) : 0;
 		return gck_attribute_set_ulong (attr, handle);
 
-	case CKA_G_USES_REMAINING:
-		if (self->pv->uses_remaining < 0)
-			return gck_attribute_set_ulong (attr, (CK_ULONG)-1);
-		else
-			return gck_attribute_set_ulong (attr, self->pv->uses_remaining);
-
 	case CKA_VALUE:
 		return CKR_ATTRIBUTE_SENSITIVE;
 	};
@@ -181,7 +188,6 @@ static void
 gck_credential_init (GckCredential *self)
 {
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_CREDENTIAL, GckCredentialPrivate);
-	self->pv->uses_remaining = -1;
 }
 
 static void
@@ -193,14 +199,7 @@ gck_credential_dispose (GObject *obj)
 		g_object_weak_unref (G_OBJECT (self->pv->object), object_went_away, self);
 	self->pv->object = NULL;
 
-	if (self->pv->secret)
-		g_object_unref (self->pv->secret);
-	self->pv->secret = NULL;
-
-	if (self->pv->user_data && self->pv->destroy)
-		(self->pv->destroy)(self->pv->user_data);
-	self->pv->user_data = NULL;
-	self->pv->destroy = NULL;
+	clear_data (self);
 
 	G_OBJECT_CLASS (gck_credential_parent_class)->dispose (obj);
 }
@@ -211,9 +210,8 @@ gck_credential_finalize (GObject *obj)
 	GckCredential *self = GCK_CREDENTIAL (obj);
 
 	g_assert (!self->pv->object);
-	g_assert (!self->pv->secret);
+	g_assert (!self->pv->user_type);
 	g_assert (!self->pv->user_data);
-	g_assert (!self->pv->destroy);
 
 	G_OBJECT_CLASS (gck_credential_parent_class)->finalize (obj);
 }
@@ -255,9 +253,6 @@ gck_credential_get_property (GObject *obj, guint prop_id, GValue *value,
 	case PROP_SECRET:
 		g_value_set_object (value, gck_credential_get_secret (self));
 		break;
-	case PROP_USES_REMAINING:
-		g_value_set_int (value, gck_credential_get_uses_remaining (self));
-		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -288,10 +283,6 @@ gck_credential_class_init (GckCredentialClass *klass)
 	g_object_class_install_property (gobject_class, PROP_SECRET,
 	           g_param_spec_object ("secret", "Secret", "Optiontal secret",
 	                                GCK_TYPE_SECRET, G_PARAM_READWRITE));
-
-	g_object_class_install_property (gobject_class, PROP_USES_REMAINING,
-	           g_param_spec_int ("uses-remaining", "Uses Remaining", "Uses remaining",
-	                             -1, G_MAXINT, -1, G_PARAM_READWRITE));
 }
 
 /* -----------------------------------------------------------------------------
@@ -410,47 +401,124 @@ gck_credential_get_object (GckCredential *self)
 	return self->pv->object;
 }
 
-gint
-gck_credential_get_uses_remaining (GckCredential *self)
+gpointer
+gck_credential_peek_data (GckCredential *self, GType type)
 {
-	g_return_val_if_fail (GCK_IS_CREDENTIAL (self), 0);
-	return self->pv->uses_remaining;
+	g_return_val_if_fail (GCK_IS_CREDENTIAL (self), NULL);
+	if (!self->pv->user_data)
+		return NULL;
+	g_return_val_if_fail (type == self->pv->user_type, NULL);
+	return self->pv->user_data;
 }
 
-void
-gck_credential_set_uses_remaining (GckCredential *self, gint use_count)
+gpointer
+gck_credential_pop_data (GckCredential *self, GType type)
 {
-	g_return_if_fail (GCK_IS_CREDENTIAL (self));
-	g_return_if_fail (use_count != 0);
+	gpointer data = NULL;
+	g_return_val_if_fail (GCK_IS_CREDENTIAL (self), NULL);
 
-	self->pv->uses_remaining = use_count;
-	g_object_notify (G_OBJECT (self), "uses-remaining");
+	if (self->pv->user_data) {
+		g_return_val_if_fail (type == self->pv->user_type, NULL);
+		if (G_TYPE_IS_BOXED (self->pv->user_type))
+			data = g_boxed_copy (self->pv->user_type, self->pv->user_data);
+		else if (G_TYPE_IS_OBJECT (self->pv->user_type))
+			data = g_object_ref (self->pv->user_data);
+		else
+			g_assert_not_reached ();
+	}
+
+	gck_object_mark_used (GCK_OBJECT (self));
+	return data;
 }
 
 void
-gck_credential_throw_away_one_use (GckCredential *self)
+gck_credential_set_data (GckCredential *self, GType type, gpointer data)
 {
 	g_return_if_fail (GCK_IS_CREDENTIAL (self));
-	if (self->pv->uses_remaining > 0)
-		--(self->pv->uses_remaining);
-	if (self->pv->uses_remaining == 0)
-		self_destruct (self);
-}
 
-gpointer
-gck_credential_get_data (GckCredential *self)
-{
-	g_return_val_if_fail (GCK_IS_CREDENTIAL (self), NULL);
-	return self->pv->user_data;
+	if (data) {
+		g_return_if_fail (type);
+		g_return_if_fail (G_TYPE_IS_BOXED (type) || G_TYPE_IS_OBJECT (type));
+	}
+
+	clear_data (self);
+
+	if (data) {
+		self->pv->user_type = type;
+		if (G_TYPE_IS_BOXED (type))
+			self->pv->user_data = g_boxed_copy (type, data);
+		else if (G_TYPE_IS_OBJECT (type))
+			self->pv->user_data = g_object_ref (data);
+		else
+			g_assert_not_reached ();
+	}
 }
 
-void
-gck_credential_set_data (GckCredential *self, gpointer data, GDestroyNotify destroy)
+gboolean
+gck_credential_for_each (GckSession *session, GckObject *object,
+                         GckCredentialFunc func, gpointer user_data)
 {
-	g_return_if_fail (GCK_IS_CREDENTIAL (self));
+	CK_OBJECT_HANDLE handle;
+	CK_OBJECT_CLASS klass;
+	CK_ATTRIBUTE attrs[2];
+	GList *results, *l;
+	GckCredential *cred;
+	gboolean ret;
+
+	g_return_val_if_fail (GCK_IS_SESSION (session), FALSE);
+	g_return_val_if_fail (GCK_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (func, FALSE);
+
+	/* Do we have one right on the session */
+	cred = gck_session_get_credential (session);
+	if (cred && gck_credential_get_object (cred) == object) {
+		g_object_ref (cred);
+		ret = (func) (cred, object, user_data);
+		g_object_unref (cred);
+		if (ret)
+			return TRUE;
+	}
+
+	klass = CKO_G_CREDENTIAL;
+	attrs[0].type = CKA_CLASS;
+	attrs[0].pValue = &klass;
+	attrs[0].ulValueLen = sizeof (klass);
+
+	handle = gck_object_get_handle (object);
+	attrs[1].type = CKA_G_OBJECT;
+	attrs[1].pValue = &handle;
+	attrs[1].ulValueLen = sizeof (handle);
+
+	/* Find any on the session */
+	results = gck_manager_find_by_attributes (gck_session_get_manager (session),
+	                                          attrs, G_N_ELEMENTS (attrs));
+
+	for (l = results; l; l = g_list_next (l)) {
+		g_object_ref (l->data);
+		ret = (func) (l->data, object, user_data);
+		g_object_unref (l->data);
+		if (ret)
+			break;
+	}
+
+	g_list_free (results);
+
+	if (l != NULL)
+		return TRUE;
+
+	/* Find any in the token */
+	results = gck_manager_find_by_attributes (gck_module_get_manager (gck_session_get_module (session)),
+	                                          attrs, G_N_ELEMENTS (attrs));
+
+	for (l = results; l; l = g_list_next (l)) {
+		g_object_ref (l->data);
+		ret = (func) (l->data, object, user_data);
+		g_object_unref (l->data);
+		if (ret)
+			break;
+	}
+
+	g_list_free (results);
 
-	if (self->pv->user_data && self->pv->destroy)
-		(self->pv->destroy) (self->pv->user_data);
-	self->pv->user_data = data;
-	self->pv->destroy = destroy;
+	return (l != NULL);
 }
diff --git a/pkcs11/gck/gck-credential.h b/pkcs11/gck/gck-credential.h
index c20e03e..01d5589 100644
--- a/pkcs11/gck/gck-credential.h
+++ b/pkcs11/gck/gck-credential.h
@@ -72,17 +72,24 @@ const gchar*               gck_credential_get_password           (GckCredential
 
 GckObject*                 gck_credential_get_object             (GckCredential *self);
 
-gpointer                   gck_credential_get_data               (GckCredential *self);
+gpointer                   gck_credential_peek_data              (GckCredential *self,
+                                                                  GType type);
+
+gpointer                   gck_credential_pop_data               (GckCredential *self,
+                                                                  GType type);
 
 void                       gck_credential_set_data               (GckCredential *self,
-                                                                  gpointer data,
-                                                                  GDestroyNotify destroy);
+                                                                  GType type,
+                                                                  gpointer data);
 
-gint                       gck_credential_get_uses_remaining     (GckCredential *self);
+typedef gboolean           (*GckCredentialFunc)                  (GckCredential *cred,
+                                                                  GckObject *object,
+                                                                  gpointer user_data);
 
-void                       gck_credential_set_uses_remaining     (GckCredential *self,
-                                                                  gint use_count);
 
-void                       gck_credential_throw_away_one_use     (GckCredential *self);
+gboolean                   gck_credential_for_each               (GckSession *self,
+                                                                  GckObject *object,
+                                                                  GckCredentialFunc func,
+                                                                  gpointer user_data);
 
 #endif /* __GCK_CREDENTIAL_H__ */
diff --git a/pkcs11/gck/gck-object.c b/pkcs11/gck/gck-object.c
index 2d28df3..0b2544f 100644
--- a/pkcs11/gck/gck-object.c
+++ b/pkcs11/gck/gck-object.c
@@ -23,8 +23,10 @@
 
 #include "pkcs11/pkcs11.h"
 #include "pkcs11/pkcs11g.h"
+#include "pkcs11/pkcs11i.h"
 
 #include "gck-attributes.h"
+#include "gck-credential.h"
 #include "gck-manager.h"
 #include "gck-object.h"
 #include "gck-transaction.h"
@@ -51,8 +53,12 @@ enum {
 static guint signals[LAST_SIGNAL] = { 0 };
 
 typedef struct _GckObjectTransient {
-	GckTimer *timed_timer;
-	glong timed_when;
+	GckTimer *timer;
+	gulong timed_after;
+	gulong timed_idle;
+	glong stamp_used;
+	glong stamp_created;
+	gulong uses_remaining;
 } GckObjectTransient;
 
 struct _GckObjectPrivate {
@@ -76,33 +82,62 @@ void  _gck_manager_unregister_object (GckManager *self, GckObject *object);
  */
 
 static void
-kaboom_callback (GckTimer *timer, gpointer user_data)
+self_destruct (GckObject *self)
 {
-	GckObject *self = user_data;
 	GckTransaction *transaction;
-	GckObjectTransient *transient;
 	CK_RV rv;
 
-	g_return_if_fail (GCK_IS_OBJECT (self));
-	g_return_if_fail (self->pv->transient);
-	transient = self->pv->transient;
-
-	g_return_if_fail (timer == transient->timed_timer);
-	transient->timed_timer = NULL;
-
-	g_object_ref (self);
-
 	transaction = gck_transaction_new ();
 
-	/* Off we go */
 	gck_object_destroy (self, transaction);
 
 	gck_transaction_complete (transaction);
 	rv = gck_transaction_get_result (transaction);
 	g_object_unref (transaction);
-
 	if (rv != CKR_OK)
 		g_warning ("Unexpected failure to auto destruct object (code: %lu)", (gulong)rv);
+}
+
+static void
+timer_callback (GckTimer *timer, gpointer user_data)
+{
+	GckObject *self = user_data;
+	glong after, idle, offset;
+	GckObjectTransient *transient;
+	GTimeVal tv;
+
+	g_return_if_fail (GCK_IS_OBJECT (self));
+
+	g_object_ref (self);
+
+	g_return_if_fail (self->pv->transient);
+	transient = self->pv->transient;
+	g_return_if_fail (timer == transient->timer);
+	transient->timer = NULL;
+
+	g_get_current_time (&tv);
+	idle = after = G_MAXLONG;
+
+	/* Are we supposed to be destroyed after a certain time? */
+	if (transient->timed_after) {
+		g_return_if_fail (transient->stamp_created);
+		after = (transient->stamp_created + transient->timed_after) - tv.tv_sec;
+	}
+
+	/* Are we supposed to be destroyed after an idle time? */
+	if (transient->timed_idle) {
+		g_return_if_fail (transient->stamp_used);
+		idle = (transient->stamp_used + transient->timed_idle) - tv.tv_sec;
+	}
+
+	/* Okay, time to destroy? */
+	offset = MIN (after, idle);
+	if (offset <= 0)
+		self_destruct (self);
+
+	/* Setup the next timer */
+	else
+		transient->timer = gck_timer_start (self->pv->module, offset, timer_callback, self);
 
 	g_object_unref (self);
 }
@@ -112,15 +147,19 @@ start_callback (GckTransaction *transaction, GObject *obj, gpointer user_data)
 {
 	GckObject *self = GCK_OBJECT (obj);
 	GckObjectTransient *transient;
+	GTimeVal tv;
 
 	g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE);
 	g_return_val_if_fail (self->pv->transient, FALSE);
 	transient = self->pv->transient;
+	g_return_val_if_fail (!transient->timer, FALSE);
 
-	g_return_val_if_fail (!transient->timed_timer, FALSE);
-	transient->timed_timer = gck_timer_start (self->pv->module, transient->timed_when, 
-	                                          kaboom_callback, self);
+	g_get_current_time (&tv);
+	transient->stamp_created = tv.tv_sec;
+	transient->stamp_used = tv.tv_sec;
 
+	/* Start the timer going */
+	timer_callback (NULL, self);
 	return TRUE;
 }
 
@@ -153,6 +192,15 @@ complete_expose (GckTransaction *transaction, GObject *obj, gpointer user_data)
 	return TRUE;
 }
 
+static gboolean
+find_credential (GckCredential *cred, GckObject *object, gpointer user_data)
+{
+	CK_OBJECT_HANDLE *result = user_data;
+	g_return_val_if_fail (!*result, FALSE);
+	*result = gck_object_get_handle (GCK_OBJECT (cred));
+	return TRUE;
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT 
  */
@@ -160,8 +208,9 @@ complete_expose (GckTransaction *transaction, GObject *obj, gpointer user_data)
 static CK_RV 
 gck_object_real_get_attribute (GckObject *self, GckSession *session, CK_ATTRIBUTE* attr)
 {
+	CK_OBJECT_HANDLE handle = 0;
 	CK_RV rv;
-	
+
 	switch (attr->type)
 	{
 	case CKA_CLASS:
@@ -173,15 +222,24 @@ gck_object_real_get_attribute (GckObject *self, GckSession *session, CK_ATTRIBUT
 		return gck_attribute_set_bool (attr, FALSE);
 	case CKA_TOKEN:
 		return gck_attribute_set_bool (attr, gck_object_is_token (self));
+	case CKA_G_CREDENTIAL:
+		gck_credential_for_each (session, GCK_OBJECT (self), find_credential, &handle);
+		return gck_attribute_set_ulong (attr, handle);
 	case CKA_GNOME_UNIQUE:
 		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->transient ?
-		                                     self->pv->transient->timed_when : -1);
+	case CKA_G_DESTRUCT_AFTER:
+		return gck_attribute_set_ulong (attr, self->pv->transient ?
+		                                      self->pv->transient->timed_after : 0);
+	case CKA_G_DESTRUCT_IDLE:
+		return gck_attribute_set_ulong (attr, self->pv->transient ?
+		                                      self->pv->transient->timed_idle : 0);
+	case CKA_G_DESTRUCT_USES:
+		return gck_attribute_set_ulong (attr, self->pv->transient ?
+		                                      self->pv->transient->uses_remaining : 0);
 	};
 
 	/* Give store a shot */
@@ -250,9 +308,9 @@ gck_object_real_create_attributes (GckObject *self, GckSession *session,
                                    GckTransaction *transaction, CK_ATTRIBUTE *attrs, CK_ULONG n_attrs)
 {
 	CK_ATTRIBUTE_PTR transient_attr;
-	CK_ATTRIBUTE_PTR lifetime_attr;
 	gboolean transient = FALSE;
-	glong lifetime = -1;
+	gulong after = 0;
+	gulong idle = 0;
 	CK_RV rv;
 
 	/* Parse the transient attribute */
@@ -267,15 +325,8 @@ gck_object_real_create_attributes (GckObject *self, GckSession *session,
 	}
 
 	/* 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;
-		}
-		
+	if (gck_attributes_find_ulong (attrs, n_attrs, CKA_G_DESTRUCT_AFTER, &after) ||
+	    gck_attributes_find_ulong (attrs, n_attrs, CKA_G_DESTRUCT_IDLE, &idle)) {
 		/* Default for the transient attribute */
 		if (!transient_attr)
 			transient = TRUE;
@@ -283,10 +334,11 @@ gck_object_real_create_attributes (GckObject *self, GckSession *session,
 
 	if (transient) {
 		self->pv->transient = g_slice_new0 (GckObjectTransient);
-		self->pv->transient->timed_when = lifetime;
+		self->pv->transient->timed_after = after;
+		self->pv->transient->timed_idle = idle;
 	}
 
-	if (lifetime >= 0) {
+	if (after || idle) {
 		if (!self->pv->transient) {
 			gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
 			return;
@@ -354,9 +406,9 @@ gck_object_dispose (GObject *obj)
 
 	if (self->pv->transient) {
 		transient = self->pv->transient;
-		if (transient->timed_timer)
-			gck_timer_cancel (transient->timed_timer);
-		transient->timed_timer = NULL;
+		if (transient->timer)
+			gck_timer_cancel (transient->timer);
+		transient->timer = NULL;
 	}
 
 	G_OBJECT_CLASS (gck_object_parent_class)->dispose (obj);
@@ -663,6 +715,28 @@ gck_object_is_transient (GckObject *self)
 	return self->pv->transient ? TRUE : FALSE;
 }
 
+void
+gck_object_mark_used (GckObject *self)
+{
+	GckObjectTransient *transient;
+	GTimeVal tv;
+
+	g_return_if_fail (GCK_IS_OBJECT (self));
+	transient = self->pv->transient;
+
+	if (transient) {
+		if (transient->timed_idle) {
+			g_get_current_time (&tv);
+			transient->stamp_used = tv.tv_sec;
+		}
+		if (transient->uses_remaining) {
+			--(transient->uses_remaining);
+			if (transient->uses_remaining == 0)
+				self_destruct (self);
+		}
+	}
+}
+
 CK_RV
 gck_object_unlock (GckObject *self, GckCredential *cred)
 {
diff --git a/pkcs11/gck/gck-object.h b/pkcs11/gck/gck-object.h
index d9b28d1..149a51e 100644
--- a/pkcs11/gck/gck-object.h
+++ b/pkcs11/gck/gck-object.h
@@ -83,6 +83,8 @@ gboolean               gck_object_is_token               (GckObject *self);
 
 gboolean               gck_object_is_transient           (GckObject *self);
 
+void                   gck_object_mark_used              (GckObject *self);
+
 CK_RV                  gck_object_unlock                 (GckObject *self,
                                                           GckCredential *cred);
 
diff --git a/pkcs11/gck/gck-private-xsa-key.c b/pkcs11/gck/gck-private-xsa-key.c
index f099d2c..5940309 100644
--- a/pkcs11/gck/gck-private-xsa-key.c
+++ b/pkcs11/gck/gck-private-xsa-key.c
@@ -176,12 +176,9 @@ acquire_from_credential (GckCredential *cred, GckObject *object, gpointer user_d
 	g_assert (!*result);
 
 	/* The sexp we stored on the credential */
-	*result = gck_credential_get_data (cred);
-	if (*result != NULL) {
-		*result = gck_sexp_ref (*result);
-		gck_credential_throw_away_one_use (cred);
+	*result = gck_credential_pop_data (cred, GCK_BOXED_SEXP);
+	if (*result != NULL)
 		return TRUE;
-	}
 
 	return FALSE;
 }
@@ -190,7 +187,7 @@ static gboolean
 have_from_credential (GckCredential *cred, GckObject *object, gpointer unused)
 {
 	/* The sexp we stored on the credential */
-	return gck_credential_get_data (cred) ? TRUE : FALSE;
+	return gck_credential_peek_data (cred, GCK_BOXED_SEXP) ? TRUE : FALSE;
 }
 
 /* -----------------------------------------------------------------------------
@@ -245,7 +242,7 @@ gck_private_xsa_key_real_get_attribute (GckObject *base, GckSession *session, CK
 	case CKA_ALWAYS_AUTHENTICATE:
 		have = self->pv->sexp ? TRUE : FALSE;
 		if (!have && session)
-			have = gck_session_for_each_credential (session, base, have_from_credential, NULL);
+			have = gck_credential_for_each (session, base, have_from_credential, NULL);
 		return gck_attribute_set_bool (attr, !have);
 
 	case CKA_MODULUS:
@@ -292,8 +289,8 @@ gck_private_xsa_key_real_acquire_crypto_sexp (GckSexpKey *base, GckSession *sess
 
 	/* Find an credential, with an unlocked copy */
 	else
-		gck_session_for_each_credential (session, GCK_OBJECT (self),
-		                                 acquire_from_credential, &sexp);
+		gck_credential_for_each (session, GCK_OBJECT (self),
+		                         acquire_from_credential, &sexp);
 
 	return sexp;
 }
@@ -368,9 +365,7 @@ gck_private_xsa_key_set_locked_private (GckPrivateXsaKey *self, GckCredential *c
 	g_return_if_fail (GCK_IS_PRIVATE_XSA_KEY (self));
 	g_return_if_fail (GCK_IS_CREDENTIAL (cred));
 	g_return_if_fail (gck_credential_get_object (cred) == GCK_OBJECT (self));
-	if (sexp != NULL)
-		gck_sexp_ref (sexp);
-	gck_credential_set_data (cred, sexp, gck_sexp_unref);
+	gck_credential_set_data (cred, GCK_BOXED_SEXP, sexp);
 }
 
 GckSexp*
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index fee6766..8b280ec 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -756,62 +756,11 @@ gck_session_destroy_session_object (GckSession *self, GckTransaction *transactio
 	remove_object (self, transaction, obj);
 }
 
-gboolean
-gck_session_for_each_credential (GckSession *self, GckObject *object,
-                                 GckCredentialFunc func, gpointer user_data)
+GckCredential*
+gck_session_get_credential (GckSession *self)
 {
-	CK_OBJECT_HANDLE handle;
-	CK_OBJECT_CLASS klass;
-	CK_ATTRIBUTE attrs[2];
-	GList *results, *l;
-
-	g_return_val_if_fail (GCK_IS_SESSION (self), FALSE);
-	g_return_val_if_fail (GCK_IS_OBJECT (object), FALSE);
-	g_return_val_if_fail (func, FALSE);
-
-	/* Do we have one right on the session */
-	if (self->pv->credential != NULL &&
-	    gck_credential_get_object (self->pv->credential) == object) {
-		if ((func) (self->pv->credential, object, user_data))
-			return TRUE;
-	}
-
-	klass = CKO_G_CREDENTIAL;
-	attrs[0].type = CKA_CLASS;
-	attrs[0].pValue = &klass;
-	attrs[0].ulValueLen = sizeof (klass);
-
-	handle = gck_object_get_handle (object);
-	attrs[1].type = CKA_G_OBJECT;
-	attrs[1].pValue = &handle;
-	attrs[1].ulValueLen = sizeof (handle);
-
-	/* Find any on the session */
-	results = gck_manager_find_by_attributes (self->pv->manager,
-	                                          attrs, G_N_ELEMENTS (attrs));
-
-	for (l = results; l; l = g_list_next (l)) {
-		if ((func) (l->data, object, user_data))
-			break;
-	}
-
-	g_list_free (results);
-
-	if (l != NULL)
-		return TRUE;
-
-	/* Find any in the token */
-	results = gck_manager_find_by_attributes (gck_module_get_manager (self->pv->module), 
-	                                          attrs, G_N_ELEMENTS (attrs));
-
-	for (l = results; l; l = g_list_next (l)) {
-		if ((func) (l->data, object, user_data))
-			break;
-	}
-
-	g_list_free (results);
-	
-	return (l != NULL);
+	g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
+	return self->pv->credential;
 }
 
 GckObject*
diff --git a/pkcs11/gck/gck-session.h b/pkcs11/gck/gck-session.h
index 348c312..290443d 100644
--- a/pkcs11/gck/gck-session.h
+++ b/pkcs11/gck/gck-session.h
@@ -52,10 +52,6 @@ struct _GckSessionClass {
 #endif
 };
 
-typedef gboolean         (*GckCredentialFunc)                           (GckCredential *cred,
-                                                                         GckObject *object,
-                                                                         gpointer user_data);
-
 GType                    gck_session_get_type                           (void);
 
 GckSession*              gck_session_for_session_object                 (GckObject *obj);
@@ -85,6 +81,8 @@ void                     gck_session_set_crypto_state                   (GckSess
                                                                          gpointer state,
                                                                          GDestroyNotify destroy);
 
+GckCredential*           gck_session_get_credential                     (GckSession *self);
+
 CK_RV                    gck_session_lookup_readable_object             (GckSession *self, 
                                                                          CK_OBJECT_HANDLE handle, 
                                                                          GckObject **result);
@@ -105,11 +103,6 @@ void                     gck_session_destroy_session_object             (GckSess
                                                                          GckTransaction *transaction,
                                                                          GckObject *obj);
 
-gboolean                 gck_session_for_each_credential                (GckSession *self,
-                                                                         GckObject *object,
-                                                                         GckCredentialFunc func,
-                                                                         gpointer user_data);
-
 GckObject*               gck_session_create_object_for_factory          (GckSession *self,
                                                                          GckFactory *factory,
                                                                          GckTransaction *transaction,
diff --git a/pkcs11/gck/gck-timer.c b/pkcs11/gck/gck-timer.c
index 4776c3b..999670b 100644
--- a/pkcs11/gck/gck-timer.c
+++ b/pkcs11/gck/gck-timer.c
@@ -157,15 +157,18 @@ gck_timer_shutdown (void)
 GMutex* _gck_module_get_scary_mutex_that_you_should_not_touch (GckModule *self);
 
 GckTimer*
-gck_timer_start (GckModule *module, glong when, GckTimerFunc callback, gpointer user_data)
+gck_timer_start (GckModule *module, glong seconds, GckTimerFunc callback, gpointer user_data)
 {
 	GckTimer *timer;
+	GTimeVal tv;
 
 	g_return_val_if_fail (callback, NULL);
 	g_return_val_if_fail (timer_queue, NULL);
 
+	g_get_current_time (&tv);
+
 	timer = g_slice_new (GckTimer);
-	timer->when = when;
+	timer->when = seconds + tv.tv_sec;
 	timer->callback = callback;
 	timer->user_data = user_data;
 
diff --git a/pkcs11/gck/gck-timer.h b/pkcs11/gck/gck-timer.h
index 14fdf93..170db4e 100644
--- a/pkcs11/gck/gck-timer.h
+++ b/pkcs11/gck/gck-timer.h
@@ -30,7 +30,7 @@ typedef void    (*GckTimerFunc)                (GckTimer *timer,
                                                 gpointer user_data); 
 
 GckTimer*       gck_timer_start                (GckModule *module, 
-                                                glong when,
+                                                glong seconds,
                                                 GckTimerFunc func, 
                                                 gpointer user_data);
 
diff --git a/pkcs11/gck/tests/unit-test-credential.c b/pkcs11/gck/tests/unit-test-credential.c
index 6601339..0e1d9ff 100644
--- a/pkcs11/gck/tests/unit-test-credential.c
+++ b/pkcs11/gck/tests/unit-test-credential.c
@@ -32,7 +32,7 @@
 #include "gck/gck-session.h"
 #include "gck/gck-module.h"
 
-#include "pkcs11g.h"
+#include "pkcs11i.h"
 
 static GckModule *module = NULL;
 static GckSession *session = NULL;
@@ -174,40 +174,6 @@ DEFINE_TEST(credential_get_attributes)
 	g_assert (rv == CKR_OK);
 	g_assert (check.ulValueLen == sizeof (value));
 	g_assert (value == locked);
-
-	check.type = CKA_G_USES_REMAINING;
-	check.pValue = &value;
-	check.ulValueLen = sizeof (value);
-
-	rv = gck_session_C_GetAttributeValue (session, handle, &check, 1);
-	g_assert (rv == CKR_OK);
-	g_assert (check.ulValueLen == sizeof (value));
-	g_assert (value == (CK_ULONG)-1);
-}
-
-DEFINE_TEST(credential_uses_property)
-{
-	GckCredential *auth;
-	gint uses;
-	CK_RV rv;
-
-	rv = gck_credential_create (module, NULL, object, (guchar*)"mock", 4, &auth);
-	g_assert (rv == CKR_OK);
-	g_assert (auth);
-
-	g_object_get (auth, "uses-remaining", &uses, NULL);
-	g_assert (uses == -1);
-
-	gck_credential_set_uses_remaining (auth, 5);
-
-	uses = gck_credential_get_uses_remaining (auth);
-	g_assert (uses == 5);
-
-	gck_credential_throw_away_one_use (auth);
-	uses = gck_credential_get_uses_remaining (auth);
-	g_assert (uses == 4);
-
-	g_object_unref (auth);
 }
 
 DEFINE_TEST(credential_object_property)
@@ -262,26 +228,43 @@ DEFINE_TEST(credential_login_property)
 	g_object_unref (cred);
 }
 
+static GType
+boxed_string (void)
+{
+	static GType type = 0;
+	if (!type)
+		type = g_boxed_type_register_static ("TestBoxedString",
+		                                     (GBoxedCopyFunc)g_strdup,
+		                                     (GBoxedFreeFunc)g_free);
+	return type;
+}
+
 DEFINE_TEST(credential_data)
 {
 	GckCredential *cred;
+	GType type = boxed_string ();
+	gchar *check;
 	CK_RV rv;
 
 	rv = gck_credential_create (module, NULL, object, (guchar*)"mock", 4, &cred);
 	g_assert (rv == CKR_OK);
 	g_assert (cred);
 
-	g_assert (gck_credential_get_data (cred) == NULL);
+	g_assert (gck_credential_peek_data (cred, type) == NULL);
+
+	gck_credential_set_data (cred, type, "one");
 
-	gck_credential_set_data (cred, g_strdup ("one"), g_free);
+	check = gck_credential_pop_data (cred, type);
+	g_assert_cmpstr ("one", ==, check);
+	g_free (check);
 
-	g_assert_cmpstr ("one", ==, gck_credential_get_data (cred));
+	g_assert_cmpstr ("one", ==, gck_credential_peek_data (cred, type));
 
-	gck_credential_set_data (cred, g_strdup ("ONE"), g_free);
-	g_assert_cmpstr ("ONE", ==, gck_credential_get_data (cred));
+	gck_credential_set_data (cred, type, "ONE");
+	g_assert_cmpstr ("ONE", ==, gck_credential_peek_data (cred, type));
 
-	gck_credential_set_data (cred, NULL, NULL);
-	g_assert (gck_credential_get_data (cred) == NULL);
+	gck_credential_set_data (cred, 0, NULL);
+	g_assert (gck_credential_peek_data (cred, 0) == NULL);
 
 	g_object_unref (cred);
 }
diff --git a/pkcs11/gck/tests/unit-test-object.c b/pkcs11/gck/tests/unit-test-object.c
index ee1dea1..fd16dd0 100644
--- a/pkcs11/gck/tests/unit-test-object.c
+++ b/pkcs11/gck/tests/unit-test-object.c
@@ -30,7 +30,7 @@
 #include "gck/gck-module.h"
 #include "gck/gck-transaction.h"
 
-#include "pkcs11g.h"
+#include "pkcs11i.h"
 
 static GckModule *module = NULL;
 static GckSession *session = NULL;
@@ -157,12 +157,12 @@ 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_ULONG lifetime = 2;
+	CK_ULONG check;
+
 	CK_ATTRIBUTE attrs[] = {
-       		{ CKA_GNOME_AUTO_DESTRUCT, lifetime, sizeof (lifetime) },
-	        { CKA_TOKEN, &token, sizeof (token) },
+		{ CKA_G_DESTRUCT_AFTER, &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 },
@@ -171,19 +171,13 @@ DEFINE_TEST(object_create_auto_destruct)
 	CK_BBOOL transient;
 	
 	CK_ATTRIBUTE lookups[] = { 
-		{ CKA_GNOME_AUTO_DESTRUCT, check, sizeof (check) },
+		{ CKA_G_DESTRUCT_AFTER, &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);
@@ -194,7 +188,7 @@ DEFINE_TEST(object_create_auto_destruct)
 	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);
+	g_assert (memcmp (&lifetime, &check, sizeof (lifetime)) == 0);
 	
 	test_module_leave ();
 	test_mainloop_run (2200);
@@ -207,10 +201,11 @@ 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_BBOOL transient = CK_FALSE;
+	CK_ULONG after = 1;
+
 	CK_ATTRIBUTE attrs[] = {
-       		{ CKA_GNOME_AUTO_DESTRUCT, "1999010101010100", 16 },
+		{ CKA_G_DESTRUCT_AFTER, &after, sizeof (after) },
 		{ CKA_GNOME_TRANSIENT, &transient, sizeof (transient) },
 		{ CKA_CLASS, &klass, sizeof (klass) },
 		{ CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
@@ -225,26 +220,6 @@ DEFINE_TEST(object_create_auto_destruct_not_transient)
 	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);
-}
-
 DEFINE_TEST(object_expose)
 {
 	CK_OBJECT_HANDLE handle;
diff --git a/pkcs11/gck/tests/unit-test-timer.c b/pkcs11/gck/tests/unit-test-timer.c
index f9b42cf..ac50b62 100644
--- a/pkcs11/gck/tests/unit-test-timer.c
+++ b/pkcs11/gck/tests/unit-test-timer.c
@@ -55,12 +55,10 @@ timer_callback (GckTimer *timer, gpointer user_data)
 
 DEFINE_TEST(timer_simple)
 {
-	GTimeVal tv;
 	GckTimer *timer;
-	
-	g_get_current_time (&tv);
-	timer = gck_timer_start (module, tv.tv_sec + 2, timer_callback, &timer);
-	
+
+	timer = gck_timer_start (module, 2, timer_callback, &timer);
+
 	test_module_leave ();
 	test_mainloop_run (2200);
 	test_module_enter ();
@@ -70,12 +68,10 @@ DEFINE_TEST(timer_simple)
 
 DEFINE_TEST(timer_cancel)
 {
-	GTimeVal tv;
 	GckTimer *timer;
-	
-	g_get_current_time (&tv);
-	timer = gck_timer_start (module, tv.tv_sec + 2, timer_callback, &timer);
-	
+
+	timer = gck_timer_start (module, 2, timer_callback, &timer);
+
 	test_module_leave ();
 	test_mainloop_run (500);
 	test_module_enter ();
@@ -92,13 +88,11 @@ DEFINE_TEST(timer_cancel)
 
 DEFINE_TEST(timer_immediate)
 {
-	GTimeVal tv;
 	GckTimer *timer;
-	
+
 	/* Setup timer in the past, should execute as soon as possible */
-	g_get_current_time (&tv);
-	timer = gck_timer_start (module, tv.tv_sec - 5, timer_callback, &timer);
-	
+	timer = gck_timer_start (module, -5, timer_callback, &timer);
+
 	/* Should not be called immediately */
 	g_assert (timer != NULL);
 	
@@ -126,16 +120,13 @@ multiple_callback (GckTimer *timer, gpointer user_data)
 
 DEFINE_TEST(timer_multiple)
 {
-	GTimeVal tv;
-	
 	timer_check = 0;
-	g_get_current_time (&tv);
-	
+
 	/* Multiple timers, add out of order, should be called in order */
-	gck_timer_start (module, tv.tv_sec + 1, multiple_callback, GINT_TO_POINTER (1));
-	gck_timer_start (module, tv.tv_sec + 3, multiple_callback, GINT_TO_POINTER (3));
-	gck_timer_start (module, tv.tv_sec + 2, multiple_callback, GINT_TO_POINTER (2));
-	gck_timer_start (module, tv.tv_sec + 0, multiple_callback, GINT_TO_POINTER (0));
+	gck_timer_start (module, 1, multiple_callback, GINT_TO_POINTER (1));
+	gck_timer_start (module, 3, multiple_callback, GINT_TO_POINTER (3));
+	gck_timer_start (module, 2, multiple_callback, GINT_TO_POINTER (2));
+	gck_timer_start (module, 0, multiple_callback, GINT_TO_POINTER (0));
 	
 	test_module_leave ();
 	test_mainloop_run (3500);
@@ -146,12 +137,8 @@ DEFINE_TEST(timer_multiple)
 
 DEFINE_TEST(timer_outstanding)
 {
-	GTimeVal tv;
-	
-	g_get_current_time (&tv);
-
 	/* A timer that can't be called */
-	gck_timer_start (module, tv.tv_sec + 5, timer_callback, NULL);
-	gck_timer_start (module, tv.tv_sec + 10, timer_callback, NULL);
-	gck_timer_start (module, tv.tv_sec + 1, timer_callback, NULL);
+	gck_timer_start (module, 5, timer_callback, NULL);
+	gck_timer_start (module, 10, timer_callback, NULL);
+	gck_timer_start (module, 1, timer_callback, NULL);
 }
diff --git a/pkcs11/pkcs11g.h b/pkcs11/pkcs11g.h
index a84e7d9..f9f0ffc 100644
--- a/pkcs11/pkcs11g.h
+++ b/pkcs11/pkcs11g.h
@@ -90,23 +90,8 @@
 #define CKA_GNOME_PURPOSE_TIME_STAMPING          (CKA_GNOME + 109)
 
 /* -------------------------------------------------------------------
- * AUTO-DESTRUCT
  */
 
-#define CKA_GNOME_AUTO_DESTRUCT                  (CKA_GNOME + 200)
-
 #define CKA_GNOME_TRANSIENT                      (CKA_GNOME + 201)
 
-/* -------------------------------------------------------------------
- * CREDENTIAL
- */
-
-#define CKO_G_CREDENTIAL                         (CKO_GNOME + 100)
-
-#define CKA_G_OBJECT                             (CKA_GNOME + 202)
-
-#define CKA_G_USES_REMAINING                     (CKA_GNOME + 203)
-
-#define CKA_G_CREDENTIAL                         (CKA_GNOME + 204)
-
 #endif /* PKCS11G_H */
diff --git a/pkcs11/pkcs11i.h b/pkcs11/pkcs11i.h
index a32e4f9..08337f1 100644
--- a/pkcs11/pkcs11i.h
+++ b/pkcs11/pkcs11i.h
@@ -95,4 +95,26 @@ typedef CK_G_APPLICATION* CK_G_APPLICATION_PTR;
 
 #define CKK_G_NULL                           (CKK_GNOME + 100)
 
+/* -------------------------------------------------------------------
+ * AUTO DESTRUCT
+ */
+
+#define CKA_G_DESTRUCT_IDLE                  (CKA_GNOME + 190)
+
+#define CKA_G_DESTRUCT_AFTER                 (CKA_GNOME + 191)
+
+#define CKA_G_DESTRUCT_USES                  (CKA_GNOME + 192)
+
+/* -------------------------------------------------------------------
+ * CREDENTIAL
+ */
+
+#define CKO_G_CREDENTIAL                         (CKO_GNOME + 100)
+
+#define CKA_G_OBJECT                             (CKA_GNOME + 202)
+
+#define CKA_G_CREDENTIAL                         (CKA_GNOME + 204)
+
+#define CKA_G_CREDENTIAL_TEMPLATE                (CKA_GNOME + 205)
+
 #endif /* PKCS11I_H */
diff --git a/pkcs11/secret-store/gck-secret-binary.c b/pkcs11/secret-store/gck-secret-binary.c
index 6e68594..d8fa13f 100644
--- a/pkcs11/secret-store/gck-secret-binary.c
+++ b/pkcs11/secret-store/gck-secret-binary.c
@@ -587,19 +587,19 @@ gck_secret_binary_write (GckSecretCollection *collection, GckSecretData *sdata,
 	egg_buffer_append (&buffer, (guchar*)KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN);
 	egg_buffer_add_byte (&buffer, 0); /* Major version */
 	egg_buffer_add_byte (&buffer, 0); /* Minor version */
-	egg_buffer_add_byte (&buffer, 0); /* crypto (0 == AEL) */
+	egg_buffer_add_byte (&buffer, 0); /* crypto (0 == AES) */
 	egg_buffer_add_byte (&buffer, 0); /* hash (0 == MD5) */
 
 	buffer_add_utf8_string (&buffer, gck_secret_object_get_label (obj));
 	buffer_add_time (&buffer, gck_secret_object_get_modified (obj));
 	buffer_add_time (&buffer, gck_secret_object_get_created (obj));
-	
+
 	flags = 0;
-	if (g_object_get_data (G_OBJECT (collection), "lock-on-idle")) 
-		flags |= 1;
+	lock_timeout = gck_secret_collection_get_lock_idle (collection);
+	if (lock_timeout)
+		flags |= LOCK_ON_IDLE_FLAG;
 	egg_buffer_add_uint32 (&buffer, flags);
-	
-	lock_timeout = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (collection), "lock-on-idle"));
+
 	egg_buffer_add_uint32 (&buffer, lock_timeout);
 	egg_buffer_add_uint32 (&buffer, hash_iterations);
 	egg_buffer_append (&buffer, salt, 8);
@@ -939,8 +939,9 @@ gck_secret_binary_read (GckSecretCollection *collection, GckSecretData *sdata,
 	gck_secret_object_set_label (obj, display_name);
 	gck_secret_object_set_modified (obj, mtime);
 	gck_secret_object_set_created (obj, ctime);
-	g_object_set_data (G_OBJECT (collection), "lock-on-idle", GINT_TO_POINTER (!!(flags & LOCK_ON_IDLE_FLAG)));
-	g_object_set_data (G_OBJECT (collection), "lock-timeout", GINT_TO_POINTER (lock_timeout));
+	if (!(flags & LOCK_ON_IDLE_FLAG))
+		lock_timeout = 0;
+	gck_secret_collection_set_lock_idle (collection, lock_timeout);
 
 	/* Build a Hash table where we can track ids we haven't yet seen */
 	checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
diff --git a/pkcs11/secret-store/gck-secret-collection.c b/pkcs11/secret-store/gck-secret-collection.c
index 23fc457..d418ab1 100644
--- a/pkcs11/secret-store/gck-secret-collection.c
+++ b/pkcs11/secret-store/gck-secret-collection.c
@@ -48,6 +48,11 @@ struct _GckSecretCollection {
 	GHashTable *items;
 	gchar *filename;
 	guint32 watermark;
+
+	/* Template for credential */
+	CK_ATTRIBUTE tp_attrs[2];
+	CK_ULONG tp_idle;
+	CK_BBOOL tp_token;
 };
 
 G_DEFINE_TYPE (GckSecretCollection, gck_secret_collection, GCK_TYPE_SECRET_OBJECT);
@@ -108,7 +113,7 @@ find_unlocked_credential (GckCredential *cred, GckObject *object, gpointer user_
 
 	g_return_val_if_fail (!*result, FALSE);
 
-	if (gck_credential_get_data (cred)) {
+	if (gck_credential_peek_data (cred, GCK_TYPE_SECRET_DATA)) {
 		*result = gck_object_get_handle (GCK_OBJECT (cred));
 		return TRUE;
 	}
@@ -121,14 +126,12 @@ find_unlocked_secret_data (GckCredential *cred, GckObject *object, gpointer user
 {
 	GckSecretCollection *self = GCK_SECRET_COLLECTION (object);
 	GckSecretData **result = user_data;
-	GckSecretData *sdata;
 
 	g_return_val_if_fail (!*result, FALSE);
 
-	sdata = gck_credential_get_data (cred);
-	if (sdata) {
-		g_return_val_if_fail (sdata == self->sdata, FALSE);
-		*result = sdata;
+	*result = gck_credential_pop_data (cred, GCK_TYPE_SECRET_DATA);
+	if (*result) {
+		g_return_val_if_fail (*result == self->sdata, FALSE);
 		return TRUE;
 	}
 
@@ -292,9 +295,10 @@ factory_create_collection (GckSession *session, GckTransaction *transaction,
 
 	gck_credential_connect (cred, GCK_OBJECT (collection));
 	sdata = g_object_new (GCK_TYPE_SECRET_DATA, NULL);
-	gck_credential_set_data (cred, sdata, g_object_unref);
+	gck_credential_set_data (cred, GCK_TYPE_SECRET_DATA, sdata);
 	gck_secret_data_set_master (sdata, gck_credential_get_secret (cred));
 	track_secret_data (collection, sdata);
+	g_object_unref (sdata);
 
 	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (collection), attrs, n_attrs);
 	return GCK_OBJECT (collection);
@@ -335,7 +339,7 @@ change_master_password (GckSecretCollection *self, GckTransaction *transaction,
 		g_object_ref (previous);
 
 	gck_credential_connect (cred, GCK_OBJECT (self));
-	gck_credential_set_data (cred, g_object_ref (self->sdata), g_object_unref);
+	gck_credential_set_data (cred, GCK_TYPE_SECRET_DATA, self->sdata);
 	gck_secret_data_set_master (self->sdata, gck_credential_get_secret (cred));
 
 	gck_transaction_add (transaction, self, complete_master_password, previous);
@@ -349,15 +353,12 @@ static CK_RV
 gck_secret_collection_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBUTE_PTR attr)
 {
 	GckSecretCollection *self = GCK_SECRET_COLLECTION (base);
-	CK_OBJECT_HANDLE handle = 0;
 
 	switch (attr->type) {
 	case CKA_CLASS:
 		return gck_attribute_set_ulong (attr, CKO_G_COLLECTION);
-	case CKA_G_CREDENTIAL:
-		gck_session_for_each_credential (session, GCK_OBJECT (self),
-		                                 find_unlocked_credential, &handle);
-		return gck_attribute_set_ulong (attr, handle);
+	case CKA_G_CREDENTIAL_TEMPLATE:
+		return gck_attribute_set_template (attr, self->tp_attrs, G_N_ELEMENTS (self->tp_attrs));
 	}
 	return GCK_OBJECT_CLASS (gck_secret_collection_parent_class)->get_attribute (base, session, attr);
 }
@@ -373,8 +374,8 @@ gck_secret_collection_set_attribute (GckObject *object, GckSession *session,
 
 	switch (attr->type) {
 	case CKA_G_CREDENTIAL:
-		gck_session_for_each_credential (session, GCK_OBJECT (self),
-		                                 find_unlocked_credential, &handle);
+		gck_credential_for_each (session, GCK_OBJECT (self),
+		                         find_unlocked_credential, &handle);
 		if (handle == 0)
 			return gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
 		rv = gck_attribute_get_ulong (attr, &handle);
@@ -397,6 +398,7 @@ gck_secret_collection_real_unlock (GckObject *obj, GckCredential *cred)
 	GckDataResult res;
 	GckSecretData *sdata;
 	GckSecret *master;
+	CK_RV rv;
 
 	master = gck_credential_get_secret (cred);
 
@@ -406,7 +408,7 @@ gck_secret_collection_real_unlock (GckObject *obj, GckCredential *cred)
 			return CKR_PIN_INCORRECT;
 
 		/* Credential now tracks our secret data */
-		gck_credential_set_data (cred, g_object_ref (self->sdata), g_object_unref);
+		gck_credential_set_data (cred, GCK_TYPE_SECRET_DATA, self->sdata);
 		return CKR_OK;
 	}
 
@@ -428,23 +430,27 @@ gck_secret_collection_real_unlock (GckObject *obj, GckCredential *cred)
 
 	switch (res) {
 	case GCK_DATA_SUCCESS:
-		gck_credential_set_data (cred, sdata, g_object_unref);
+		gck_credential_set_data (cred, GCK_TYPE_SECRET_DATA, sdata);
 		track_secret_data (self, sdata);
-		return CKR_OK;
+		rv = CKR_OK;
+		break;
 	case GCK_DATA_LOCKED:
-		g_object_unref (sdata);
-		return CKR_PIN_INCORRECT;
+		rv = CKR_PIN_INCORRECT;
+		break;
 	case GCK_DATA_UNRECOGNIZED:
-		g_object_unref (sdata);
 		g_message ("unrecognized or invalid keyring: %s", self->filename);
-		return CKR_FUNCTION_FAILED;
+		rv = CKR_FUNCTION_FAILED;
+		break;
 	case GCK_DATA_FAILURE:
-		g_object_unref (sdata);
 		g_message ("failed to read or parse keyring: %s", self->filename);
-		return CKR_GENERAL_ERROR;
+		rv = CKR_GENERAL_ERROR;
+		break;
 	default:
 		g_assert_not_reached ();
 	}
+
+	g_object_unref (sdata);
+	return rv;
 }
 
 static void
@@ -458,15 +464,24 @@ static gboolean
 gck_secret_collection_real_is_locked (GckSecretObject *obj, GckSession *session)
 {
 	GckSecretCollection *self = GCK_SECRET_COLLECTION (obj);
-	return gck_secret_collection_unlocked_data (self, session) ? FALSE : TRUE;
+	return gck_secret_collection_unlocked_have (self, session);
 }
 
 static void
 gck_secret_collection_init (GckSecretCollection *self)
 {
 	self->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-}
 
+	self->tp_token = CK_FALSE;
+	self->tp_attrs[0].type = CKA_TOKEN;
+	self->tp_attrs[0].pValue = &self->tp_token;
+	self->tp_attrs[0].ulValueLen = sizeof (self->tp_token);
+
+	self->tp_idle = 0;
+	self->tp_attrs[1].type = CKA_G_DESTRUCT_IDLE;
+	self->tp_attrs[1].pValue = &self->tp_idle;
+	self->tp_attrs[1].ulValueLen = sizeof (self->tp_idle);
+}
 
 static void
 gck_secret_collection_set_property (GObject *obj, guint prop_id, const GValue *value,
@@ -727,8 +742,26 @@ gck_secret_collection_destroy_item (GckSecretCollection *self, GckTransaction *t
 	remove_item (self, transaction, item);
 }
 
+gboolean
+gck_secret_collection_unlocked_have (GckSecretCollection *self, GckSession *session)
+{
+	CK_OBJECT_HANDLE handle = 0;
+
+	g_return_val_if_fail (GCK_IS_SECRET_COLLECTION (self), FALSE);
+	g_return_val_if_fail (GCK_IS_SESSION (session), FALSE);
+
+	/*
+	 * Look for credential objects that this session has access
+	 * to, and use those to find the secret data. If a secret data is
+	 * found, it should match the one we are tracking in self->sdata.
+	 */
+
+	gck_credential_for_each (session, GCK_OBJECT (self), find_unlocked_credential, &handle);
+	return handle != 0;
+}
+
 GckSecretData*
-gck_secret_collection_unlocked_data (GckSecretCollection *self, GckSession *session)
+gck_secret_collection_unlocked_use (GckSecretCollection *self, GckSession *session)
 {
 	GckSecretData *sdata = NULL;
 
@@ -741,8 +774,8 @@ gck_secret_collection_unlocked_data (GckSecretCollection *self, GckSession *sess
 	 * found, it should match the one we are tracking in self->sdata.
 	 */
 
-	gck_session_for_each_credential (session, GCK_OBJECT (self),
-	                                 find_unlocked_secret_data, &sdata);
+	gck_credential_for_each (session, GCK_OBJECT (self),
+	                         find_unlocked_secret_data, &sdata);
 
 	return sdata;
 }
@@ -827,3 +860,19 @@ gck_secret_collection_destroy (GckSecretCollection *self, GckTransaction *transa
 	if (self->filename)
 		gck_transaction_remove_file (transaction, self->filename);
 }
+
+gint
+gck_secret_collection_get_lock_idle (GckSecretCollection *self)
+{
+	g_return_val_if_fail (GCK_IS_SECRET_COLLECTION (self), 0);
+	return (gint)self->tp_idle;
+}
+
+void
+gck_secret_collection_set_lock_idle (GckSecretCollection *self, gint lock_timeout)
+{
+	g_return_if_fail (GCK_IS_SECRET_COLLECTION (self));
+	if (lock_timeout < 0)
+		lock_timeout = 0;
+	self->tp_idle = (CK_ULONG)lock_timeout;
+}
diff --git a/pkcs11/secret-store/gck-secret-collection.h b/pkcs11/secret-store/gck-secret-collection.h
index 98d9cf5..e0a8e57 100644
--- a/pkcs11/secret-store/gck-secret-collection.h
+++ b/pkcs11/secret-store/gck-secret-collection.h
@@ -85,7 +85,15 @@ void                 gck_secret_collection_destroy_item    (GckSecretCollection
 
 void                 gck_secret_collection_unlocked_clear  (GckSecretCollection *self);
 
-GckSecretData*       gck_secret_collection_unlocked_data   (GckSecretCollection *self,
+GckSecretData*       gck_secret_collection_unlocked_use    (GckSecretCollection *self,
                                                             GckSession *session);
 
+gboolean             gck_secret_collection_unlocked_have   (GckSecretCollection *self,
+                                                            GckSession *session);
+
+gint                 gck_secret_collection_get_lock_idle   (GckSecretCollection *self);
+
+void                 gck_secret_collection_set_lock_idle   (GckSecretCollection *self,
+                                                            gint lock_timeout);
+
 #endif /* __GCK_SECRET_COLLECTION_H__ */
diff --git a/pkcs11/secret-store/gck-secret-item.c b/pkcs11/secret-store/gck-secret-item.c
index a6605d8..b0c5659 100644
--- a/pkcs11/secret-store/gck-secret-item.c
+++ b/pkcs11/secret-store/gck-secret-item.c
@@ -207,6 +207,7 @@ gck_secret_item_real_get_attribute (GckObject *base, GckSession *session, CK_ATT
 	const gchar *identifier;
 	const guchar *secret;
 	gsize n_secret = 0;
+	CK_RV rv;
 
 	g_return_val_if_fail (self->collection, CKR_GENERAL_ERROR);
 
@@ -215,12 +216,14 @@ gck_secret_item_real_get_attribute (GckObject *base, GckSession *session, CK_ATT
 		return gck_attribute_set_ulong (attr, CKO_SECRET_KEY);
 
 	case CKA_VALUE:
-		sdata = gck_secret_collection_unlocked_data (self->collection, session);
+		sdata = gck_secret_collection_unlocked_use (self->collection, session);
 		if (sdata == NULL)
 			return CKR_USER_NOT_LOGGED_IN;
 		identifier = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (self));
 		secret = gck_secret_data_get_raw (sdata, identifier, &n_secret);
-		return gck_attribute_set_data (attr, secret, n_secret);
+		rv = gck_attribute_set_data (attr, secret, n_secret);
+		g_object_unref (sdata);
+		return rv;
 
 	case CKA_G_COLLECTION:
 		g_return_val_if_fail (self->collection, CKR_GENERAL_ERROR);
@@ -257,18 +260,20 @@ gck_secret_item_real_set_attribute (GckObject *base, GckSession *session,
 	}
 
 	/* Check that the object is not locked */
-	sdata = gck_secret_collection_unlocked_data (self->collection, session);
-	if (sdata == NULL) {
+	if (!gck_secret_collection_unlocked_have (self->collection, session)) {
 		gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
 		return;
 	}
 
 	switch (attr->type) {
 	case CKA_VALUE:
+		sdata = gck_secret_collection_unlocked_use (self->collection, session);
+		g_return_if_fail (sdata);
 		identifier = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (self));
 		secret = gck_secret_new (attr->pValue, attr->ulValueLen);
 		gck_secret_data_set_transacted (sdata, transaction, identifier, secret);
 		g_object_unref (secret);
+		g_object_unref (sdata);
 		if (!gck_transaction_get_failed (transaction))
 			gck_transaction_add (transaction, self, complete_set_secret, NULL);
 		return;
diff --git a/pkcs11/secret-store/gck-secret-textual.c b/pkcs11/secret-store/gck-secret-textual.c
index 029e46a..6c4e7d1 100644
--- a/pkcs11/secret-store/gck-secret-textual.c
+++ b/pkcs11/secret-store/gck-secret-textual.c
@@ -390,7 +390,6 @@ gck_secret_textual_write (GckSecretCollection *collection, GckSecretData *sdata,
 	const gchar *value;
 	GKeyFile *file;
 	GError *err = NULL;
-	gboolean idle_lock;
 	gint idle_timeout;
 
 	g_return_val_if_fail (GCK_IS_SECRET_COLLECTION (collection), GCK_DATA_FAILURE);
@@ -408,8 +407,8 @@ gck_secret_textual_write (GckSecretCollection *collection, GckSecretData *sdata,
 	key_file_set_uint64 (file, "keyring", "mtime", gck_secret_object_get_modified (obj));
 
 	/* Not currently used :( */
-	idle_lock = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (collection), "lock-on-idle"));
-	g_key_file_set_boolean (file, "keyring", "lock-on-idle", idle_lock);
+	idle_timeout = gck_secret_collection_get_lock_idle (collection);
+	g_key_file_set_boolean (file, "keyring", "lock-on-idle", idle_timeout > 0);
 	idle_timeout = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (collection), "lock-timeout"));
 	g_key_file_set_integer (file, "keyring", "lock-timeout", idle_timeout);
 
diff --git a/pkcs11/secret-store/tests/unit-test-secret-collection.c b/pkcs11/secret-store/tests/unit-test-secret-collection.c
index 9c8136c..0a77d28 100644
--- a/pkcs11/secret-store/tests/unit-test-secret-collection.c
+++ b/pkcs11/secret-store/tests/unit-test-secret-collection.c
@@ -115,9 +115,10 @@ DEFINE_TEST(secret_collection_unlocked_data)
 	g_object_unref (cred);
 
 	/* Collection should now be unlocked */
-	sdata = gck_secret_collection_unlocked_data (collection, session);
+	sdata = gck_secret_collection_unlocked_use (collection, session);
 	g_assert (GCK_IS_SECRET_DATA (sdata));
 	g_assert (!gck_secret_object_is_locked (GCK_SECRET_OBJECT (collection), session));
+	g_object_unref (sdata);
 }
 
 DEFINE_TEST(secret_collection_get_filename)
@@ -177,9 +178,10 @@ DEFINE_TEST(secret_collection_load_unlock_plain)
 	gck_session_add_session_object (session, NULL, GCK_OBJECT (cred));
 	g_object_unref (cred);
 
-	sdata = gck_secret_collection_unlocked_data (collection, session);
+	sdata = gck_secret_collection_unlocked_use (collection, session);
 	g_assert (sdata != NULL && GCK_IS_SECRET_DATA (sdata));
 	test_secret_collection_validate (collection, sdata);
+	g_object_unref (sdata);
 }
 
 DEFINE_TEST(secret_collection_load_unlock_encrypted)
@@ -205,9 +207,10 @@ DEFINE_TEST(secret_collection_load_unlock_encrypted)
 	gck_session_add_session_object (session, NULL, GCK_OBJECT (cred));
 	g_object_unref (cred);
 
-	sdata = gck_secret_collection_unlocked_data (collection, session);
+	sdata = gck_secret_collection_unlocked_use (collection, session);
 	g_assert (sdata != NULL && GCK_IS_SECRET_DATA (sdata));
 	test_secret_collection_validate (collection, sdata);
+	g_object_unref (sdata);
 }
 
 DEFINE_TEST(secret_collection_load_unlock_bad_password)
@@ -249,9 +252,10 @@ DEFINE_TEST(secret_collection_unlock_without_load)
 	gck_session_add_session_object (session, NULL, GCK_OBJECT (cred));
 	g_object_unref (cred);
 
-	sdata = gck_secret_collection_unlocked_data (collection, session);
+	sdata = gck_secret_collection_unlocked_use (collection, session);
 	g_assert (sdata != NULL && GCK_IS_SECRET_DATA (sdata));
 	test_secret_collection_validate (collection, sdata);
+	g_object_unref (sdata);
 }
 
 DEFINE_TEST(secret_collection_twice_unlock)
@@ -279,9 +283,10 @@ DEFINE_TEST(secret_collection_twice_unlock)
 	gck_session_add_session_object (session, NULL, GCK_OBJECT (cred));
 	g_object_unref (cred);
 
-	sdata = gck_secret_collection_unlocked_data (collection, session);
+	sdata = gck_secret_collection_unlocked_use (collection, session);
 	g_assert (sdata != NULL && GCK_IS_SECRET_DATA (sdata));
 	test_secret_collection_validate (collection, sdata);
+	g_object_unref (sdata);
 }
 
 DEFINE_TEST(secret_collection_twice_unlock_bad_password)
@@ -307,9 +312,10 @@ DEFINE_TEST(secret_collection_twice_unlock_bad_password)
 	                            (guchar*)"wrong", 5, &cred);
 	g_assert (rv == CKR_PIN_INCORRECT);
 
-	sdata = gck_secret_collection_unlocked_data (collection, session);
+	sdata = gck_secret_collection_unlocked_use (collection, session);
 	g_assert (sdata != NULL && GCK_IS_SECRET_DATA (sdata));
 	test_secret_collection_validate (collection, sdata);
+	g_object_unref (sdata);
 }
 
 DEFINE_TEST(secret_collection_memory_unlock)



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