diff --git a/egg/egg-asn1.c b/egg/egg-asn1.c
index fc4708f..bbc4989 100644
--- a/egg/egg-asn1.c
+++ b/egg/egg-asn1.c
@@ -413,7 +413,8 @@ two_to_four_digit_year (int year)
 }
 
 #ifndef HAVE_TIMEGM
-time_t timegm(struct tm *t)
+static time_t 
+timegm (struct tm *t)
 {
 	time_t tl, tb;
 	struct tm *tg;
diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am
index f264a53..54fd7c8 100644
--- a/pkcs11/gck/Makefile.am
+++ b/pkcs11/gck/Makefile.am
@@ -18,6 +18,7 @@ BUILT_SOURCES = \
 
 libgck_la_SOURCES = \
 	gck-attributes.c gck-attributes.h \
+	gck-auto-destruct.c gck-auto-destruct.h \
 	gck-certificate.c gck-certificate.h \
 	gck-certificate-key.c gck-certificate-key.h \
 	gck-certificate-trust.c gck-certificate-trust.h \
@@ -40,6 +41,7 @@ libgck_la_SOURCES = \
 	gck-session.c gck-session.h \
 	gck-sexp.c gck-sexp.h \
 	gck-store.c gck-store.h \
+	gck-timer.c gck-timer.h \
 	gck-transaction.c gck-transaction.h \
 	gck-types.h \
 	gck-util.c gck-util.h \
diff --git a/pkcs11/gck/gck-attributes.c b/pkcs11/gck/gck-attributes.c
index ad1b9de..014d684 100644
--- a/pkcs11/gck/gck-attributes.c
+++ b/pkcs11/gck/gck-attributes.c
@@ -28,6 +28,71 @@
 #include <stdio.h>
 #include <string.h>
 
+#ifndef HAVE_TIMEGM
+static time_t 
+timegm (struct tm *t)
+{
+	time_t tl, tb;
+	struct tm *tg;
+
+	tl = mktime (t);
+	if (tl == -1)
+	{
+		t->tm_hour--;
+		tl = mktime (t);
+		if (tl == -1)
+			return -1; /* can't deal with output from strptime */
+		tl += 3600;
+	}
+	tg = gmtime (&tl);
+	tg->tm_isdst = 0;
+	tb = mktime (tg);
+	if (tb == -1)
+	{
+		tg->tm_hour--;
+		tb = mktime (tg);
+		if (tb == -1)
+			return -1; /* can't deal with output from gmtime */
+		tb += 3600;
+	}
+	return (tl - (tb - tl));
+}
+#endif // NOT_HAVE_TIMEGM
+
+CK_RV
+gck_attribute_get_time (CK_ATTRIBUTE_PTR attr, glong *when)
+{
+	struct tm tm;
+	gchar buf[15];
+	time_t time;
+
+	g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (when, CKR_GENERAL_ERROR);
+	
+	if (!attr->pValue && attr->ulValueLen == 0) {
+		*when = (glong)-1;
+		return CKR_OK;
+	}
+	
+	if (!attr->pValue || attr->ulValueLen != 16)
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+	
+	memset (&tm, 0, sizeof (tm));
+	memcpy (buf, attr->pValue, 14);
+	buf[14] = 0;
+	
+	if (!strptime(buf, "%Y%m%d%H%M%S", &tm))
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+	
+	/* Convert to seconds since epoch */
+	time = timegm (&tm);
+	if (time < 0)
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+	
+	*when = time;
+	return CKR_OK;
+}
+
 CK_RV
 gck_attribute_set_bool (CK_ATTRIBUTE_PTR attr, CK_BBOOL value)
 {
@@ -80,6 +145,32 @@ gck_attribute_set_date (CK_ATTRIBUTE_PTR attr, time_t time)
 		
 	return gck_attribute_set_data (attr, &date, sizeof (date));
 }
+
+CK_RV
+gck_attribute_set_time (CK_ATTRIBUTE_PTR attr, glong when)
+{
+	struct tm tm;
+	gchar buf[20];
+	
+	/* 'Empty' time as defined in PKCS#11 */
+	if (when == (glong)-1)
+		return gck_attribute_set_data (attr, NULL, 0);
+		
+	if (!attr->pValue) {
+		attr->ulValueLen = 16;
+		return CKR_OK;
+	}
+
+	time_t time = when;
+	if (!gmtime_r (&time, &tm))
+		g_return_val_if_reached (CKR_GENERAL_ERROR);
+	
+	if (!strftime(buf, sizeof (buf), "%Y%m%d%H%M%S00", &tm))
+		g_return_val_if_reached (CKR_GENERAL_ERROR);
+	
+	return gck_attribute_set_data (attr, buf, 16);
+}
+
 CK_RV
 gck_attribute_set_data (CK_ATTRIBUTE_PTR attr, gconstpointer value, gsize n_value)
 {
diff --git a/pkcs11/gck/gck-attributes.h b/pkcs11/gck/gck-attributes.h
index 81b84a7..a3be756 100644
--- a/pkcs11/gck/gck-attributes.h
+++ b/pkcs11/gck/gck-attributes.h
@@ -28,6 +28,9 @@
 
 #include "pkcs11/pkcs11.h"
 
+CK_RV                 gck_attribute_get_time                           (CK_ATTRIBUTE_PTR attr,
+                                                                        glong *when);
+
 CK_RV                 gck_attribute_set_bool                           (CK_ATTRIBUTE_PTR attr,
                                                                         CK_BBOOL value);
 
@@ -40,6 +43,9 @@ CK_RV                 gck_attribute_set_string                         (CK_ATTRI
 CK_RV                 gck_attribute_set_date                           (CK_ATTRIBUTE_PTR attr,
                                                                         time_t when);
 
+CK_RV                 gck_attribute_set_time                           (CK_ATTRIBUTE_PTR attr,
+                                                                        glong when);
+
 CK_RV                 gck_attribute_set_data                           (CK_ATTRIBUTE_PTR attr,
                                                                         gconstpointer value,
                                                                         gsize n_value);
diff --git a/pkcs11/gck/gck-auto-destruct.c b/pkcs11/gck/gck-auto-destruct.c
new file mode 100644
index 0000000..8b08ae2
--- /dev/null
+++ b/pkcs11/gck/gck-auto-destruct.c
@@ -0,0 +1,322 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-auto-destruct.h"
+#include "gck-factory.h"
+#include "gck-manager.h"
+#include "gck-session.h"
+#include "gck-timer.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+#include "pkcs11/pkcs11.h"
+#include "pkcs11/pkcs11g.h"
+
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_WHEN,
+	PROP_OBJECT
+};
+
+struct _GckAutoDestructPrivate {
+	GckObject *object;
+	GckTimer *timer;
+	gulong when;
+};
+
+G_DEFINE_TYPE (GckAutoDestruct, gck_auto_destruct, GCK_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static void
+kaboom_callback (GckTimer *timer, gpointer user_data)
+{
+	GckAutoDestruct *self = user_data;
+	GckTransaction *transaction;
+	GckSession *session;
+	CK_RV rv;
+	
+	g_return_if_fail (GCK_IS_AUTO_DESTRUCT (self));
+	g_return_if_fail (timer == self->pv->timer);
+	
+	g_object_ref (self);
+	
+	transaction = gck_transaction_new ();
+	
+	if (self->pv->object) {
+		session = gck_session_for_session_object (self->pv->object);
+		g_return_if_fail (session);
+		gck_session_destroy_session_object (session, transaction, self->pv->object);
+	}
+	
+	if (!gck_transaction_get_failed (transaction)) {
+		session = gck_session_for_session_object (GCK_OBJECT (self));
+		g_return_if_fail (session);
+		gck_session_destroy_session_object (session, transaction, GCK_OBJECT (self));
+	}
+	
+	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);
+	
+	g_object_run_dispose (G_OBJECT (self));
+	g_object_unref (self);
+}
+
+static gboolean
+start_callback (GckTransaction *transaction, GObject *obj, gpointer user_data)
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (obj);
+	GckModule *module = user_data;
+	
+	g_return_val_if_fail (GCK_IS_AUTO_DESTRUCT (self), FALSE);
+	g_return_val_if_fail (GCK_IS_MODULE (module), FALSE);
+	
+	g_return_val_if_fail (!self->pv->timer, FALSE);
+	self->pv->timer = gck_timer_start (module, self->pv->when, kaboom_callback, self);
+	
+	return TRUE;
+}
+
+static void
+factory_create_auto_destruct (GckSession *session, GckTransaction *transaction, 
+                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **result)
+{
+	CK_OBJECT_HANDLE handle;
+	CK_ATTRIBUTE_PTR attr;
+	GckAutoDestruct *ad;
+	GckObject *object;
+	gboolean token;
+	glong when;
+	CK_RV rv;
+	
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (attrs || !n_attrs);
+	g_return_if_fail (result);
+	
+	/* Dig out the when the object will destruct */
+	attr = gck_attributes_find (attrs, n_attrs, CKA_GNOME_WHEN);
+	if (attr == NULL) 
+		rv = CKR_TEMPLATE_INCOMPLETE;
+	else
+		rv = gck_attribute_get_time (attr, &when);
+	if (rv != CKR_OK) {
+		gck_transaction_fail (transaction, rv);
+		return;
+	}
+		
+	/* Dig out the object itself */ 
+	if (gck_attributes_find_ulong (attrs, n_attrs, CKA_GNOME_OBJECT, &handle))
+		rv = gck_session_lookup_writable_object (session, handle, &object);
+	else
+		rv = CKR_TEMPLATE_INCOMPLETE;
+	if (rv != CKR_OK) {
+		gck_transaction_fail (transaction, rv);
+		return;
+	}
+
+	/* It must be a session object */
+	if (!gck_object_get_attribute_boolean (object, CKA_TOKEN, &token) || token) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+		return;
+	}
+	
+	ad = g_object_new (GCK_TYPE_AUTO_DESTRUCT, "when", when, "object", object, NULL);
+	
+	/* Note that we ignore the subject */
+ 	gck_attributes_consume (attrs, n_attrs, CKA_GNOME_OBJECT, CKA_TOKEN, CKA_GNOME_WHEN, G_MAXULONG);
+
+ 	gck_transaction_add (transaction, ad, start_callback, gck_session_get_module (session));
+ 	
+ 	*result = GCK_OBJECT (ad);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static CK_RV 
+gck_auto_destruct_real_get_attribute (GckObject *base, CK_ATTRIBUTE* attr)
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (base);
+	
+	switch (attr->type) {
+	
+	case CKA_CLASS:
+		return gck_attribute_set_ulong (attr, CKO_GNOME_AUTO_DESTRUCT);
+		
+	case CKA_PRIVATE:
+		return gck_attribute_set_bool (attr, TRUE);
+	
+	case CKA_GNOME_WHEN:
+		return gck_attribute_set_time (attr, self->pv->when);
+		
+	case CKA_GNOME_OBJECT:
+		return gck_attribute_set_ulong (attr, gck_object_get_handle (self->pv->object));
+	};
+
+	return GCK_OBJECT_CLASS (gck_auto_destruct_parent_class)->get_attribute (base, attr);
+}
+
+static GObject* 
+gck_auto_destruct_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (G_OBJECT_CLASS (gck_auto_destruct_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);
+	
+
+	return G_OBJECT (self);
+}
+
+static void
+gck_auto_destruct_init (GckAutoDestruct *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_AUTO_DESTRUCT, GckAutoDestructPrivate);
+}
+
+static void
+gck_auto_destruct_dispose (GObject *obj)
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (obj);
+	
+	if (self->pv->timer)
+		gck_timer_cancel (self->pv->timer);
+	self->pv->timer = NULL;
+	
+	if (self->pv->object)
+		g_object_remove_weak_pointer (G_OBJECT (self->pv->object),
+		                              (gpointer*)&(self->pv->object));
+	self->pv->object = NULL;
+	
+	G_OBJECT_CLASS (gck_auto_destruct_parent_class)->dispose (obj);
+}
+
+static void
+gck_auto_destruct_finalize (GObject *obj)
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (obj);
+	
+	g_assert (!self->pv->timer);
+	g_assert (!self->pv->object);
+
+	G_OBJECT_CLASS (gck_auto_destruct_parent_class)->finalize (obj);
+}
+
+static void
+gck_auto_destruct_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                              GParamSpec *pspec)
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (obj);
+	
+	switch (prop_id) {
+	case PROP_WHEN:
+		g_return_if_fail (!self->pv->when);
+		self->pv->when = g_value_get_long (value);
+		break;
+	case PROP_OBJECT:
+		g_return_if_fail (!self->pv->object);
+		self->pv->object = g_value_get_object (value);
+		g_return_if_fail (self->pv->object);
+		g_object_add_weak_pointer (G_OBJECT (self->pv->object),
+		                           (gpointer*)&(self->pv->object));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_auto_destruct_get_property (GObject *obj, guint prop_id, GValue *value, 
+                              GParamSpec *pspec)
+{
+	GckAutoDestruct *self = GCK_AUTO_DESTRUCT (obj);
+
+	switch (prop_id) {
+	case PROP_WHEN:
+		g_value_set_long (value, self->pv->when);
+		break;
+	case PROP_OBJECT:
+		g_value_set_object (value, self->pv->object);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_auto_destruct_class_init (GckAutoDestructClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+	
+	gck_auto_destruct_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GckAutoDestructPrivate));
+
+	gobject_class->constructor = gck_auto_destruct_constructor;
+	gobject_class->dispose = gck_auto_destruct_dispose;
+	gobject_class->finalize = gck_auto_destruct_finalize;
+	gobject_class->set_property = gck_auto_destruct_set_property;
+	gobject_class->get_property = gck_auto_destruct_get_property;
+	
+	gck_class->get_attribute = gck_auto_destruct_real_get_attribute;
+    
+	g_object_class_install_property (gobject_class, PROP_WHEN,
+	           g_param_spec_long ("when", "When", "When the auto destruct occurs", 
+	                              0, G_MAXLONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	
+	g_object_class_install_property (gobject_class, PROP_OBJECT,
+	           g_param_spec_object ("object", "Object", "Object to auto destruct", 
+	                                GCK_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GckFactoryInfo*
+gck_auto_destruct_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_GNOME_AUTO_DESTRUCT;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+	};
+
+	static GckFactoryInfo factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		factory_create_auto_destruct
+	};
+	
+	return &factory;
+}
diff --git a/pkcs11/gck/gck-auto-destruct.h b/pkcs11/gck/gck-auto-destruct.h
new file mode 100644
index 0000000..eda91b6
--- /dev/null
+++ b/pkcs11/gck/gck-auto-destruct.h
@@ -0,0 +1,55 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2009 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_AUTO_DESTRUCT_H__
+#define __GCK_AUTO_DESTRUCT_H__
+
+#include <glib-object.h>
+
+#include "gck-object.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_AUTO_DESTRUCT            (gck_auto_destruct_get_factory ())
+
+#define GCK_TYPE_AUTO_DESTRUCT               (gck_auto_destruct_get_type ())
+#define GCK_AUTO_DESTRUCT(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_AUTO_DESTRUCT, GckAutoDestruct))
+#define GCK_AUTO_DESTRUCT_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_AUTO_DESTRUCT, GckAutoDestructClass))
+#define GCK_IS_AUTO_DESTRUCT(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_AUTO_DESTRUCT))
+#define GCK_IS_AUTO_DESTRUCT_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_AUTO_DESTRUCT))
+#define GCK_AUTO_DESTRUCT_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_AUTO_DESTRUCT, GckAutoDestructClass))
+
+typedef struct _GckAutoDestructClass GckAutoDestructClass;
+typedef struct _GckAutoDestructPrivate GckAutoDestructPrivate;
+    
+struct _GckAutoDestruct {
+	GckObject parent;
+	GckAutoDestructPrivate *pv;
+};
+
+struct _GckAutoDestructClass {
+	GckObjectClass parent_class;
+};
+
+GType                      gck_auto_destruct_get_type               (void);
+
+GckFactoryInfo*            gck_auto_destruct_get_factory            (void);
+
+#endif /* __GCK_AUTO_DESTRUCT_H__ */
diff --git a/pkcs11/gck/gck-module-ep.h b/pkcs11/gck/gck-module-ep.h
index 09b5564..7ef2216 100644
--- a/pkcs11/gck/gck-module-ep.h
+++ b/pkcs11/gck/gck-module-ep.h
@@ -28,7 +28,7 @@
 #include <unistd.h>
 
 /* Forward declaration, this must be defined manually or using GCK_DEFINE_MODULE */
-static GckModule* gck_module_instantiate (CK_C_INITIALIZE_ARGS_PTR args);
+static GckModule* gck_module_instantiate (CK_C_INITIALIZE_ARGS_PTR args, GMutex *mutex);
 
 static GckModule *pkcs11_module = NULL;
 static pid_t pkcs11_module_pid = 0;
@@ -73,7 +73,7 @@ gck_C_Initialize (CK_VOID_PTR init_args)
 			else 
 				pkcs11_module_pid = pid;
 		} else {
-			pkcs11_module = gck_module_instantiate (args);
+			pkcs11_module = gck_module_instantiate (args, g_static_mutex_get_mutex (&pkcs11_module_mutex));
 			if (!pkcs11_module) {
 				g_warning ("module could not be instantiated");
 				rv = CKR_GENERAL_ERROR;
diff --git a/pkcs11/gck/gck-module.c b/pkcs11/gck/gck-module.c
index b6a06cb..07445c7 100644
--- a/pkcs11/gck/gck-module.c
+++ b/pkcs11/gck/gck-module.c
@@ -26,6 +26,7 @@
 #include "pkcs11/pkcs11i.h"
 
 #include "gck-attributes.h"
+#include "gck-auto-destruct.h"
 #include "gck-certificate.h"
 #include "gck-factory.h"
 #include "gck-manager.h"
@@ -33,6 +34,7 @@
 #include "gck-private-key.h"
 #include "gck-public-key.h"
 #include "gck-session.h"
+#include "gck-timer.h"
 #include "gck-transaction.h"
 #include "gck-util.h"
 
@@ -40,7 +42,8 @@ enum {
 	PROP_0,
 	PROP_MANAGER,
 	PROP_WRITE_PROTECTED,
-	PROP_INITIALIZE_ARGS
+	PROP_INITIALIZE_ARGS,
+	PROP_MUTEX
 };
 
 struct _GckModulePrivate {
@@ -50,6 +53,7 @@ struct _GckModulePrivate {
 	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 */
 };
 
 typedef struct _VirtualSlot {
@@ -128,6 +132,9 @@ static const MechanismAndInfo mechanism_list[] = {
 	{ CKM_DSA, { 512, 1024, CKF_SIGN | CKF_VERIFY } }
 };
 
+/* Hidden function that you should not use */
+GMutex* _gck_module_get_scary_mutex_that_you_should_not_touch (GckModule *self);
+
 /* -----------------------------------------------------------------------------
  * INTERNAL 
  */
@@ -217,7 +224,7 @@ register_virtual_slot (GckModule *self, VirtualSlot *slot)
 	g_assert (!g_hash_table_lookup (self->pv->virtual_slots_by_id, &(slot->slot_id)));
 	
 	g_hash_table_insert (self->pv->virtual_slots_by_id, 
-	                            gck_util_ulong_alloc (slot->slot_id), slot);
+	                     gck_util_ulong_alloc (slot->slot_id), slot);
 }
 
 static void
@@ -435,6 +442,8 @@ gck_module_constructor (GType type, guint n_props, GObjectConstructParam *props)
 static void
 gck_module_init (GckModule *self)
 {
+	gck_timer_initialize ();
+	
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_MODULE, GckModulePrivate);
 	self->pv->token_manager = g_object_new (GCK_TYPE_MANAGER, "for-token", TRUE, NULL);
 	self->pv->sessions_by_handle = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal, 
@@ -449,6 +458,7 @@ gck_module_init (GckModule *self)
 	gck_module_register_factory (self, GCK_FACTORY_PRIVATE_KEY);
 	gck_module_register_factory (self, GCK_FACTORY_CERTIFICATE);
 	gck_module_register_factory (self, GCK_FACTORY_PUBLIC_KEY);
+	gck_module_register_factory (self, GCK_FACTORY_AUTO_DESTRUCT);
 }
 
 static void
@@ -486,6 +496,8 @@ gck_module_finalize (GObject *obj)
 	g_array_free (self->pv->factories, TRUE);
 	self->pv->factories = NULL;
 
+	gck_timer_shutdown ();
+	
 	G_OBJECT_CLASS (gck_module_parent_class)->finalize (obj);
 }
 
@@ -502,6 +514,9 @@ gck_module_set_property (GObject *obj, guint prop_id, const GValue *value,
 		if (args != NULL && args->pReserved != NULL) 
 			parse_arguments (self, args->pReserved);
 		break;
+	case PROP_MUTEX:
+		self->pv->mutex = g_value_get_pointer (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -564,6 +579,10 @@ gck_module_class_init (GckModuleClass *klass)
 	g_object_class_install_property (gobject_class, PROP_INITIALIZE_ARGS,
 	           g_param_spec_pointer ("initialize-args", "Initialize Args", "Arguments passed to C_Initialize", 
 	                                 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+	
+	g_object_class_install_property (gobject_class, PROP_MUTEX,
+	           g_param_spec_pointer ("mutex", "Mutex", "Module mutex",
+	                                 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 /* -----------------------------------------------------------------------------
@@ -731,6 +750,18 @@ gck_module_find_factory (GckModule *self, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_att
 	return NULL;
 }
 
+/* 
+ * Hidden method to get the mutex for a module. This is for timers to be 
+ * able to reenter the module. Don't use this method. 
+ */
+
+GMutex*
+_gck_module_get_scary_mutex_that_you_should_not_touch (GckModule *self)
+{
+	g_return_val_if_fail (GCK_IS_MODULE (self), NULL);
+	return self->pv->mutex;
+}
+
 /* -----------------------------------------------------------------------------
  * PKCS#11
  */
diff --git a/pkcs11/gck/gck-module.h b/pkcs11/gck/gck-module.h
index cf877d5..c374330 100644
--- a/pkcs11/gck/gck-module.h
+++ b/pkcs11/gck/gck-module.h
@@ -94,10 +94,10 @@ struct _GckModuleClass {
 	extern const CK_FUNCTION_LIST_PTR prefix ## _function_list
 
 #define GCK_DEFINE_MODULE(prefix, type) \
-	static GckModule* gck_module_instantiate (CK_C_INITIALIZE_ARGS_PTR args) \
-		{ return g_object_new ((type), "initialize-args", args, NULL); } \
+	static GckModule* gck_module_instantiate (CK_C_INITIALIZE_ARGS_PTR args, GMutex* mutex) \
+		{ return g_object_new ((type), "initialize-args", args, "mutex", mutex, NULL); } \
 	const CK_FUNCTION_LIST_PTR prefix ## _function_list = &gck_module_function_list;
-	
+
 GType                  gck_module_get_type                        (void);
 
 GckManager*            gck_module_get_manager                     (GckModule *self);
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index 3b0744e..33d1a45 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -558,6 +558,13 @@ gck_session_class_init (GckSessionClass *klass)
  * PUBLIC 
  */
 
+GckSession*
+gck_session_for_session_object (GckObject *obj)
+{
+	g_return_val_if_fail (GCK_IS_OBJECT (obj), NULL);
+	return GCK_SESSION (g_object_get_data (G_OBJECT (obj), "owned-by-session"));
+}
+
 CK_SESSION_HANDLE
 gck_session_get_handle (GckSession *self)
 {
@@ -654,6 +661,18 @@ gck_session_login_context_specific (GckSession *self, CK_UTF8CHAR_PTR pin, CK_UL
 	return gck_object_unlock (object, pin, n_pin);
 }
 
+void
+gck_session_destroy_session_object (GckSession *self, GckTransaction *transaction,
+                                    GckObject *obj)
+{
+	g_return_if_fail (GCK_IS_SESSION (self));
+	g_return_if_fail (gck_session_for_session_object (obj) == self);
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+	
+	remove_object (self, transaction, obj);
+}
+
 /* -----------------------------------------------------------------------------
  * PKCS#11
  */
@@ -885,7 +904,7 @@ gck_session_C_DestroyObject (GckSession* self, CK_OBJECT_HANDLE handle)
 	transaction = gck_transaction_new ();
 
 	/* Lookup the actual session that owns this object, if no session, then a token object */
-	session = g_object_get_data (G_OBJECT (object), "owned-by-session");
+	session = gck_session_for_session_object (object);
 	if (session != NULL)
 		remove_object (session, transaction, object);
 	else
diff --git a/pkcs11/gck/gck-session.h b/pkcs11/gck/gck-session.h
index 6a1b327..815e62c 100644
--- a/pkcs11/gck/gck-session.h
+++ b/pkcs11/gck/gck-session.h
@@ -59,6 +59,8 @@ GckSession*              gck_session_new                                (GckModu
                                                                          CK_SLOT_ID slot_id,
                                                                          CK_FLAGS flags);
 
+GckSession*              gck_session_for_session_object                 (GckObject *obj);
+
 CK_SESSION_HANDLE        gck_session_get_handle                         (GckSession *self);
 
 CK_SLOT_ID               gck_session_get_slot_id                        (GckSession *self);
@@ -86,6 +88,9 @@ CK_RV                    gck_session_login_context_specific             (GckSess
                                                                          CK_UTF8CHAR_PTR pin,
                                                                          CK_ULONG n_pin);
 
+void                     gck_session_destroy_session_object             (GckSession *self,
+                                                                         GckTransaction *transaction,
+                                                                         GckObject *obj);
 
 
 
diff --git a/pkcs11/gck/gck-timer.c b/pkcs11/gck/gck-timer.c
new file mode 100644
index 0000000..ead15fc
--- /dev/null
+++ b/pkcs11/gck/gck-timer.c
@@ -0,0 +1,213 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2009 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General  License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General  License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-timer.h"
+
+#include <glib.h>
+
+struct _GckTimer {
+	glong when;
+	GMutex *mutex;
+	gpointer identifier;
+	GckTimerFunc callback;
+	gpointer user_data;
+};
+
+static GStaticMutex timer_mutex = G_STATIC_MUTEX_INIT;
+static GQueue *timer_queue = NULL;
+static GThread *timer_thread = NULL;
+static GCond *timer_cond = NULL;
+static gint timer_refs = 0;
+
+static gint
+compare_timers (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+	const GckTimer *ta = a;
+	const GckTimer *tb = b;
+	if (ta->when < tb->when)
+		return -1;
+	return ta->when > tb->when;
+}
+
+static gpointer
+timer_thread_func (gpointer unused)
+{
+	GMutex *mutex = g_static_mutex_get_mutex (&timer_mutex);
+	GckTimer *timer;
+	GTimeVal tv;
+	
+	g_mutex_lock (mutex);
+
+	while (timer_queue) {
+		timer = g_queue_peek_head (timer_queue);
+		
+		/* Nothing in the queue, wait until we have action */
+		if (!timer) {
+			g_cond_wait (timer_cond, mutex);
+			continue;
+		}
+		
+		g_get_current_time (&tv);
+		
+		/* We have to wait until the next timer? */
+		if (tv.tv_sec < timer->when) { 
+			tv.tv_sec = timer->when;
+			tv.tv_usec = 0;
+			g_cond_timed_wait (timer_cond, mutex, &tv);
+			continue;
+		}
+
+		/* Leave our thread mutex, and enter the module */
+		g_mutex_unlock (mutex);
+		g_mutex_lock (timer->mutex);
+
+			if (timer->callback) 
+				(timer->callback) (timer, timer->user_data);
+		
+		/* Leave the module, and go back into our thread mutex */
+		g_mutex_unlock (timer->mutex);
+		g_mutex_lock (mutex);
+
+		/* There's a chance that the timer may no longer be at head of queue */
+		g_queue_remove (timer_queue, timer);
+		g_slice_free (GckTimer, timer);
+	}
+	
+	g_mutex_unlock (mutex);
+	return NULL;
+}
+
+void
+gck_timer_initialize (void)
+{
+	GError *error = NULL;
+	g_static_mutex_lock (&timer_mutex);
+	
+		g_atomic_int_inc (&timer_refs);
+		if (!timer_thread) {
+			timer_thread = g_thread_create (timer_thread_func, NULL, TRUE, &error);
+			if (timer_thread) {
+				g_assert (timer_queue == NULL);
+				timer_queue = g_queue_new ();
+			
+				g_assert (timer_cond == NULL);
+				timer_cond = g_cond_new ();
+			} else {
+				g_warning ("could not create timer thread: %s", 
+				           error && error->message ? error->message : "");
+			}
+		}
+		
+	g_static_mutex_unlock (&timer_mutex);
+}
+
+void
+gck_timer_shutdown (void)
+{
+	if (g_atomic_int_dec_and_test (&timer_refs)) {
+		g_assert (timer_queue);
+		g_queue_free (timer_queue);
+		timer_queue = NULL;
+		
+		g_assert (timer_cond);
+		g_cond_broadcast (timer_cond);
+		
+		g_assert (timer_thread);
+		g_thread_join (timer_thread);
+		timer_thread = NULL;
+		
+		g_cond_free (timer_cond);
+		timer_cond = NULL;
+	}
+}
+
+/* We're the only caller of this function */
+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)
+{
+	GckTimer *timer;
+	
+	g_return_val_if_fail (callback, NULL);
+	g_return_val_if_fail (timer_queue, NULL);
+
+	timer = g_slice_new (GckTimer);
+	timer->when = when;
+	timer->callback = callback;
+	timer->user_data = user_data;
+
+	timer->mutex = _gck_module_get_scary_mutex_that_you_should_not_touch (module);
+	g_return_val_if_fail (timer->mutex, NULL);
+
+	g_static_mutex_lock (&timer_mutex);
+	
+		g_assert (timer_queue);
+		g_queue_insert_sorted (timer_queue, timer, compare_timers, NULL);
+		g_assert (timer_cond);
+		g_cond_broadcast (timer_cond);
+
+	g_static_mutex_unlock (&timer_mutex);
+	
+	/* 
+	 * Note that the timer thread could not already completed this timer. 
+	 * This is because we're in the module, and in order to complete a timer
+	 * the timer thread must enter the module mutex.
+	 */
+	
+	return timer;
+}
+
+void
+gck_timer_cancel (GckTimer *timer)
+{
+	GList *link;
+	
+	g_return_if_fail (timer_queue);
+
+	g_static_mutex_lock (&timer_mutex);
+	
+		g_assert (timer_queue);
+		
+		link = g_queue_find (timer_queue, timer);
+		if (link) {
+			
+			/* 
+			 * For thread safety the timer struct must be freed 
+			 * from the timer thread. So to cancel, what we do 
+			 * is move the timer to the front of the queue, 
+			 * and reset the callback and when.
+			 */
+			
+			timer->when = 0;
+			timer->callback = NULL;
+
+			g_queue_delete_link (timer_queue, link);
+			g_queue_push_head (timer_queue, timer);
+			
+			g_assert (timer_cond);
+			g_cond_broadcast (timer_cond);
+		}
+	
+	g_static_mutex_unlock (&timer_mutex);
+}
diff --git a/pkcs11/gck/gck-types.h b/pkcs11/gck/gck-types.h
index eebcce4..d783515 100644
--- a/pkcs11/gck/gck-types.h
+++ b/pkcs11/gck/gck-types.h
@@ -22,6 +22,7 @@
 #ifndef __GCK_TYPES_H__
 #define __GCK_TYPES_H__
 
+typedef struct _GckAutoDestruct GckAutoDestruct;
 typedef struct _GckCertificate GckCertificate;
 typedef struct _GckCertificateKey GckCertificateKey;
 typedef struct _GckCertificateTrust GckCertificateTrust;
@@ -38,6 +39,7 @@ typedef struct _GckSessionPrivateKey GckSessionPrivateKey;
 typedef struct _GckSessionPublicKey GckSessionPublicKey;
 typedef struct _GckSexp GckSexp;
 typedef struct _GckStore GckStore;
+typedef struct _GckTimer GckTimer;
 typedef struct _GckTransaction GckTransaction;
 
 #endif /* __GCK_TYPES_H__ */
diff --git a/pkcs11/pkcs11g.h b/pkcs11/pkcs11g.h
index 2651ef5..02ce1c4 100644
--- a/pkcs11/pkcs11g.h
+++ b/pkcs11/pkcs11g.h
@@ -97,4 +97,13 @@
 #define CKA_GNOME_PURPOSE_IPSEC_USER             (CKA_GNOME + 108)
 #define CKA_GNOME_PURPOSE_TIME_STAMPING          (CKA_GNOME + 109)
 
+/* -------------------------------------------------------------------
+ * AUTO-DESTRUCT
+ */
+
+#define CKO_GNOME_AUTO_DESTRUCT                  (CKO_GNOME + 200)
+
+#define CKA_GNOME_WHEN                           (CKA_GNOME + 200)
+#define CKA_GNOME_OBJECT                         (CKA_GNOME + 201)
+
 #endif /* PKCS11G_H */
diff --git a/pkcs11/ssh-agent/gck-ssh-agent-ops.c b/pkcs11/ssh-agent/gck-ssh-agent-ops.c
index 4fbc216..02c12d5 100644
--- a/pkcs11/ssh-agent/gck-ssh-agent-ops.c
+++ b/pkcs11/ssh-agent/gck-ssh-agent-ops.c
@@ -441,10 +441,12 @@ remove_by_public_key (GP11Session *session, GP11Object *pub, gboolean exclude_v1
 }
 
 static gboolean
-create_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pub)
+create_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pub,
+                 GArray *handles)
 {
 	GP11Object *priv_key, *pub_key;
 	GError *error = NULL;
+	CK_OBJECT_HANDLE handle;
 	
 	g_assert (GP11_IS_SESSION (session));
 	g_assert (priv);
@@ -473,7 +475,12 @@ create_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pub
 		return FALSE;
 	}
 	
+	handle = gp11_object_get_handle (pub_key);
+	g_array_append_val (handles, handle);
 	g_object_unref (pub_key);
+
+	handle = gp11_object_get_handle (priv_key);
+	g_array_append_val (handles, handle);
 	g_object_unref (priv_key);
 	
 	return TRUE;
@@ -498,7 +505,8 @@ destroy_replaced_keys (GP11Session *session, GList *keys)
 }
 
 static gboolean
-replace_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pub)
+replace_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pub,
+                  GArray *handles)
 {
 	GList *priv_prev, *pub_prev;
 	
@@ -518,7 +526,7 @@ replace_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pu
 	search_keys_like_attributes (session, priv, CKO_PUBLIC_KEY, list_all_matching, &pub_prev);
 	
 	/* Now try and create the new keys */
-	if (create_key_pair (session, priv, pub)) {
+	if (create_key_pair (session, priv, pub, handles)) {
 		
 		/* Delete the old keys */
 		destroy_replaced_keys (session, priv_prev);
@@ -531,6 +539,82 @@ replace_key_pair (GP11Session *session, GP11Attributes *priv, GP11Attributes *pu
 	return TRUE;
 }
 
+static gboolean
+load_contraints (EggBuffer *buffer, gsize offset, gsize *next_offset,
+                 glong *auto_destruct)
+{
+	GTimeVal tv;
+	guchar constraint;
+	guint32 lifetime;
+	
+	*auto_destruct = 0;
+
+	/* 
+	 * Constraints are a byte flag, and optional data depending
+	 * on the constraint. 
+	 */ 
+	
+	while (offset < egg_buffer_length (buffer)) {
+		if (!egg_buffer_get_byte (buffer, offset, &offset, &constraint))
+			return FALSE;
+		
+		switch (constraint) {
+		case GCK_SSH_FLAG_CONSTRAIN_LIFETIME:
+			if (!egg_buffer_get_uint32 (buffer, offset, &offset, &lifetime))
+				return FALSE;
+			g_get_current_time (&tv);
+			*auto_destruct = tv.tv_sec + lifetime;
+			break;
+			
+		case GCK_SSH_FLAG_CONSTRAIN_CONFIRM:
+			/* We can't use prompting as access control on an insecure X desktop */
+			g_message ("prompt constraints are not supported.");
+			return FALSE;
+			
+		default:
+			g_message ("unsupported constraint or other unsupported data");
+			return FALSE;
+		}
+	}
+
+	*next_offset = offset;
+	return TRUE;
+}
+
+static void
+setup_auto_destruct (GP11Session *session, GArray *handles, glong when)
+{
+	CK_OBJECT_HANDLE handle;
+	GError *err = NULL;
+	gchar buffer[20];
+	GP11Object *obj;
+	struct tm tm;
+	guint i;
+	
+	time_t time = when;
+	if (!gmtime_r (&time, &tm))
+		g_return_if_reached ();
+	
+	if (!strftime(buffer, sizeof (buffer), "%Y%m%d%H%M%S00", &tm))
+		g_return_if_reached ();
+	
+	for (i = 0; i < handles->len; ++i) {
+		handle = g_array_index (handles, CK_OBJECT_HANDLE, i);
+		obj = gp11_session_create_object (session, &err, 
+		                                  CKA_CLASS, GP11_ULONG, CKO_GNOME_AUTO_DESTRUCT,
+		                                  CKA_TOKEN, GP11_BOOLEAN, CK_FALSE,
+		                                  CKA_GNOME_WHEN, 16, buffer,
+		                                  CKA_GNOME_OBJECT, GP11_ULONG, handle,
+		                                  GP11_INVALID);
+		if (obj == NULL) {
+			g_warning ("couldn't create auto_destruct object: %s", err->message);
+			g_clear_error (&err);
+		} else {
+			g_object_unref (obj);
+		}
+	}
+}
+
 /* -----------------------------------------------------------------------------
  * OPERATIONS
  */
@@ -543,6 +627,8 @@ op_add_identity (GckSshAgentCall *call)
 	GP11Session *session;
 	gchar *stype = NULL;
 	gchar *comment = NULL;
+	glong auto_destruct = 0;
+	GArray *handles;
 	gboolean ret;
 	gulong algo;
 	gsize offset;
@@ -580,9 +666,6 @@ op_add_identity (GckSshAgentCall *call)
 		return FALSE;
 	}
 		
-		
-	/* TODO: Blinding? See ssh-agent.c */
-
 	/* Get the comment */
 	if (!egg_buffer_get_string (call->req, offset, &offset, &comment, (EggBufferAllocator)g_realloc)) {
 		gp11_attributes_unref (pub);
@@ -593,7 +676,16 @@ op_add_identity (GckSshAgentCall *call)
 	gp11_attributes_add_string (pub, CKA_LABEL, comment);
 	gp11_attributes_add_string (priv, CKA_LABEL, comment);
 	g_free (comment);
-		
+
+	/* Any constraints on loading the key */
+	if (!load_contraints (call->req, offset, &offset, &auto_destruct)) {
+		gp11_attributes_unref (pub);
+		gp11_attributes_unref (priv);
+		return FALSE;
+	}
+	
+	handles = g_array_new (0, 1, sizeof (CK_OBJECT_HANDLE));
+	
 	/* 
 	 * This is the session that owns these objects. Only 
 	 * one thread can use it at a time. 
@@ -602,12 +694,15 @@ op_add_identity (GckSshAgentCall *call)
 	session = gck_ssh_agent_checkout_main_session ();
 	g_return_val_if_fail (session, FALSE);
 	
-	ret = replace_key_pair (session, priv, pub);
+	ret = replace_key_pair (session, priv, pub, handles);
+	if (ret == TRUE && auto_destruct)
+		setup_auto_destruct (session, handles, auto_destruct);
 	
 	gck_ssh_agent_checkin_main_session (session);
 	
 	gp11_attributes_unref (priv);
 	gp11_attributes_unref (pub);
+	g_array_free (handles, TRUE);
 	
 	egg_buffer_add_byte (call->resp, ret ? GCK_SSH_RES_SUCCESS : GCK_SSH_RES_FAILURE);
 	return TRUE;	
@@ -618,6 +713,8 @@ op_v1_add_identity (GckSshAgentCall *call)
 {
 	GP11Attributes *pub, *priv;
 	GP11Session *session;
+	glong auto_destruct;
+	GArray *handles;
 	gboolean ret;
 	gsize offset = 5;	
 	guint32 unused;
@@ -638,6 +735,15 @@ op_v1_add_identity (GckSshAgentCall *call)
 	gp11_attributes_add_string (priv, CKA_LABEL, V1_LABEL);
 	gp11_attributes_add_string (pub, CKA_LABEL, V1_LABEL);
 	
+	/* Any constraints on loading the key */
+	if (!load_contraints (call->req, offset, &offset, &auto_destruct)) {
+		gp11_attributes_unref (pub);
+		gp11_attributes_unref (priv);
+		return FALSE;
+	}
+	
+	handles = g_array_new (0, 1, sizeof (CK_OBJECT_HANDLE));
+	
 	/* 
 	 * This is the session that owns these objects. Only 
 	 * one thread can use it at a time. 
@@ -646,12 +752,15 @@ op_v1_add_identity (GckSshAgentCall *call)
 	session = gck_ssh_agent_checkout_main_session ();
 	g_return_val_if_fail (session, FALSE);
 		
-	ret = replace_key_pair (session, priv, pub);
+	ret = replace_key_pair (session, priv, pub, handles);
+	if (ret == TRUE && auto_destruct)
+		setup_auto_destruct (session, handles, auto_destruct);
 	
 	gck_ssh_agent_checkin_main_session (session);
 	
 	gp11_attributes_unref (priv);
 	gp11_attributes_unref (pub);
+	g_array_free (handles, TRUE);
 	
 	egg_buffer_add_byte (call->resp, ret ? GCK_SSH_RES_SUCCESS : GCK_SSH_RES_FAILURE);
 	return TRUE;	
