[gnome-keyring/dbus-api] [pkcs11] Refactor object creation.



commit abc93b2ddbcfbc38cdbbfec209c189f1a14cf0d7
Author: Stef Walter <stef memberwebs com>
Date:   Thu Nov 19 18:12:02 2009 +0000

    [pkcs11] Refactor object creation.
    
    Factories are now able to recycle objects, if they match the
    attributes in specific ways. Cleanup the factory function
    signature, and the semantics of pointer ownership.

 pkcs11/gck/gck-aes-key.c                           |   28 ++--
 pkcs11/gck/gck-aes-mechanism.c                     |   11 +-
 pkcs11/gck/gck-attributes.c                        |   49 ++++--
 pkcs11/gck/gck-attributes.h                        |    8 +
 pkcs11/gck/gck-certificate.c                       |   20 +-
 pkcs11/gck/gck-credential.c                        |   21 ++-
 pkcs11/gck/gck-dh-mechanism.c                      |  168 ++++++++++++++-----
 pkcs11/gck/gck-dh-private-key.c                    |   19 ++-
 pkcs11/gck/gck-dh-public-key.c                     |   19 ++-
 pkcs11/gck/gck-factory.h                           |    4 +-
 pkcs11/gck/gck-private-xsa-key.c                   |   15 +-
 pkcs11/gck/gck-public-xsa-key.c                    |   21 ++-
 pkcs11/gck/gck-session.c                           |  186 +++++++++++---------
 pkcs11/gck/gck-session.h                           |   18 ++-
 pkcs11/gck/gck-transaction.c                       |   14 ++
 pkcs11/gck/gck-transaction.h                       |    2 +
 pkcs11/gck/tests/test-module.c                     |   13 +-
 pkcs11/secret-store/gck-secret-collection.c        |   46 +++---
 pkcs11/secret-store/gck-secret-item.c              |   28 ++--
 pkcs11/secret-store/gck-secret-search.c            |   19 +-
 .../tests/unit-test-secret-collection.c            |   98 ++++++-----
 .../secret-store/tests/unit-test-secret-search.c   |   55 +++---
 pkcs11/user-store/gck-user-private-key.c           |   21 ++-
 pkcs11/user-store/gck-user-public-key.c            |   21 ++-
 24 files changed, 549 insertions(+), 355 deletions(-)
---
diff --git a/pkcs11/gck/gck-aes-key.c b/pkcs11/gck/gck-aes-key.c
index ea14086..6274703 100644
--- a/pkcs11/gck/gck-aes-key.c
+++ b/pkcs11/gck/gck-aes-key.c
@@ -98,33 +98,39 @@ attribute_set_check_value (GckAesKey *self, CK_ATTRIBUTE *attr)
 	return rv;
 }
 
-static void
+static GckObject*
 factory_create_aes_key (GckSession *session, GckTransaction *transaction,
-                        CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                        CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckAesKey *key;
 	GckManager *manager;
 	CK_ATTRIBUTE_PTR value;
 
 	value = gck_attributes_find (attrs, n_attrs, CKA_VALUE);
-	if (value == NULL)
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+	if (value == NULL) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
 
-	if (algorithm_for_length (value->ulValueLen) == 0)
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+	if (algorithm_for_length (value->ulValueLen) == 0) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+		return NULL;
+	}
 
 	manager = gck_manager_for_template (attrs, n_attrs, session);
-	*object = g_object_new (GCK_TYPE_AES_KEY,
-	                        "module", gck_session_get_module (session),
-	                        "manager", manager,
-	                        NULL);
-	key = GCK_AES_KEY (*object);
+	key = g_object_new (GCK_TYPE_AES_KEY,
+	                    "module", gck_session_get_module (session),
+	                    "manager", manager,
+	                    NULL);
 
 	key->value = egg_secure_alloc (value->ulValueLen);
 	key->n_value = value->ulValueLen;
 	memcpy (key->value, value->pValue, key->n_value);
 
 	gck_attribute_consume (value);
+
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (key), attrs, n_attrs);
+	return GCK_OBJECT (key);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/gck/gck-aes-mechanism.c b/pkcs11/gck/gck-aes-mechanism.c
index b3bb8f1..b2c5342 100644
--- a/pkcs11/gck/gck-aes-mechanism.c
+++ b/pkcs11/gck/gck-aes-mechanism.c
@@ -25,6 +25,7 @@
 #include "gck-aes-mechanism.h"
 #include "gck-padding.h"
 #include "gck-session.h"
+#include "gck-transaction.h"
 #include "gck-util.h"
 
 #include "egg/egg-libgcrypt.h"
@@ -152,9 +153,9 @@ gck_aes_mechanism_unwrap (GckSession *session, CK_MECHANISM_PTR mech,
 	GckAesKey *key;
 	gpointer padded, value;
 	gsize n_padded, n_value;
+	GckTransaction *transaction;
 	gsize block, pos;
 	gboolean ret;
-	CK_RV rv;
 
 	g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
 	g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
@@ -212,12 +213,14 @@ gck_aes_mechanism_unwrap (GckSession *session, CK_MECHANISM_PTR mech,
 	/* Add the remainder of the attributes */
 	g_array_append_vals (array, attrs, n_attrs);
 
+	transaction = gck_transaction_new ();
+
 	/* Now create an object with these attributes */
-	rv = gck_session_create_object_for_attributes (session, (CK_ATTRIBUTE_PTR)array->data,
-	                                               array->len, unwrapped);
+	*unwrapped = gck_session_create_object_for_attributes (session, transaction,
+	                                                       (CK_ATTRIBUTE_PTR)array->data, array->len);
 
 	egg_secure_free (value);
 	g_array_free (array, TRUE);
 
-	return rv;
+	return gck_transaction_complete_and_unref (transaction);
 }
diff --git a/pkcs11/gck/gck-attributes.c b/pkcs11/gck/gck-attributes.c
index 098ca4b..0f4f60e 100644
--- a/pkcs11/gck/gck-attributes.c
+++ b/pkcs11/gck/gck-attributes.c
@@ -132,6 +132,22 @@ gck_attribute_get_string (CK_ATTRIBUTE_PTR attr, gchar **value)
 }
 
 CK_RV
+gck_attribute_get_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t *value)
+{
+	gcry_error_t gcry;
+
+	g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (value, CKR_GENERAL_ERROR);
+
+	gcry = gcry_mpi_scan (value, GCRYMPI_FMT_USG, attr->pValue, attr->ulValueLen, NULL);
+	if (gcry != 0)
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+
+	return CKR_OK;
+}
+
+
+CK_RV
 gck_attribute_set_empty (CK_ATTRIBUTE_PTR attr)
 {
 	return gck_attribute_set_data (attr, "", 0);
@@ -417,22 +433,31 @@ gck_attributes_find_ulong (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUT
 }
 
 gboolean
-gck_attributes_find_mpi (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gcry_mpi_t *value)
+gck_attributes_find_mpi (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
+                         CK_ATTRIBUTE_TYPE type, gcry_mpi_t *value)
 {
 	CK_ATTRIBUTE_PTR attr;
-	gcry_error_t gcry;
-	
+
 	g_assert (attrs || !n_attrs);
-	
+
 	attr = gck_attributes_find (attrs, n_attrs, type);
 	if (attr == NULL)
 		return FALSE;
-	
-	if (value != NULL) {
-		gcry = gcry_mpi_scan (value, GCRYMPI_FMT_USG, attr->pValue, attr->ulValueLen, NULL);
-		if (gcry != 0)
-			return FALSE;
-	}
-	
-	return TRUE;
+
+	return gck_attribute_get_mpi (attr, value) == CKR_OK;
+}
+
+gboolean
+gck_attributes_find_string (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
+                            CK_ATTRIBUTE_TYPE type, gchar **value)
+{
+	CK_ATTRIBUTE_PTR attr;
+
+	g_return_val_if_fail (attrs || !n_attrs, FALSE);
+
+	attr = gck_attributes_find (attrs, n_attrs, type);
+	if (attr == NULL)
+		return FALSE;
+
+	return gck_attribute_get_string (attr, value) == CKR_OK;
 }
diff --git a/pkcs11/gck/gck-attributes.h b/pkcs11/gck/gck-attributes.h
index 3ae7cd9..3d0d7d7 100644
--- a/pkcs11/gck/gck-attributes.h
+++ b/pkcs11/gck/gck-attributes.h
@@ -37,6 +37,9 @@ CK_RV                 gck_attribute_get_time                           (CK_ATTRI
 CK_RV                 gck_attribute_get_string                         (CK_ATTRIBUTE_PTR attr,
                                                                         gchar **value);
 
+CK_RV                 gck_attribute_get_mpi                            (CK_ATTRIBUTE_PTR attr,
+                                                                        gcry_mpi_t *value);
+
 CK_RV                 gck_attribute_set_empty                          (CK_ATTRIBUTE_PTR attr);
 
 CK_RV                 gck_attribute_set_bool                           (CK_ATTRIBUTE_PTR attr,
@@ -98,4 +101,9 @@ gboolean              gck_attributes_find_mpi                          (CK_ATTRI
                                                                         CK_ATTRIBUTE_TYPE type,
                                                                         gcry_mpi_t *mpi);
 
+gboolean              gck_attributes_find_string                       (CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        CK_ATTRIBUTE_TYPE type,
+                                                                        gchar **value);
+
 #endif /* GCK_ATTRIBUTE_H_ */
diff --git a/pkcs11/gck/gck-certificate.c b/pkcs11/gck/gck-certificate.c
index a635daf..4761731 100644
--- a/pkcs11/gck/gck-certificate.c
+++ b/pkcs11/gck/gck-certificate.c
@@ -243,22 +243,21 @@ find_certificate_extension (GckCertificate *self, GQuark oid)
 	return 0;
 }
 
-static void
+static GckObject*
 factory_create_certificate (GckSession *session, GckTransaction *transaction, 
-                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	CK_ATTRIBUTE_PTR attr;
 	GckCertificate *cert;
-	
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (object);
-	
+
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
+
 	/* Dig out the value */
 	attr = gck_attributes_find (attrs, n_attrs, CKA_VALUE);
 	if (attr == NULL) {
 		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
-		return;
+		return NULL;
 	}
 	
 	cert = g_object_new (GCK_TYPE_CERTIFICATE,
@@ -270,13 +269,14 @@ factory_create_certificate (GckSession *session, GckTransaction *transaction,
 	if (!gck_serializable_load (GCK_SERIALIZABLE (cert), NULL, attr->pValue, attr->ulValueLen)) {
 		gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
 		g_object_unref (cert);
-		return;
+		return NULL;
 	}
 		
 	/* Note that we ignore the subject */
  	gck_attributes_consume (attrs, n_attrs, CKA_VALUE, CKA_SUBJECT, G_MAXULONG);
 
- 	*object = GCK_OBJECT (cert);
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (cert), attrs, n_attrs);
+	return GCK_OBJECT (cert);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/gck/gck-credential.c b/pkcs11/gck/gck-credential.c
index 596a72b..d0e97ca 100644
--- a/pkcs11/gck/gck-credential.c
+++ b/pkcs11/gck/gck-credential.c
@@ -57,9 +57,9 @@ G_DEFINE_TYPE (GckCredential, gck_credential, GCK_TYPE_OBJECT);
  * INTERNAL
  */
 
-static void
+static GckObject*
 factory_create_credential (GckSession *session, GckTransaction *transaction,
-                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **result)
+                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	CK_OBJECT_HANDLE handle;
 	GckCredential *cred;
@@ -69,16 +69,15 @@ factory_create_credential (GckSession *session, GckTransaction *transaction,
 	GckObject *object = NULL;
 	CK_RV rv;
 
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (result);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	/* The handle is optional */
 	if (gck_attributes_find_ulong (attrs, n_attrs, CKA_G_OBJECT, &handle)) {
 		rv = gck_session_lookup_readable_object (session, handle, &object);
 		if (rv != CKR_OK) {
 			gck_transaction_fail (transaction, rv);
-			return;
+			return NULL;
 		}
 	} else {
 		object = NULL;
@@ -94,10 +93,14 @@ factory_create_credential (GckSession *session, GckTransaction *transaction,
 	rv = gck_credential_create (module, manager, object,
 	                            attr ? attr->pValue : NULL,
 	                            attr ? attr->ulValueLen : 0, &cred);
-	if (rv == CKR_OK)
-		*result = GCK_OBJECT (cred);
-	else
+
+	if (rv == CKR_OK) {
+		gck_session_complete_object_creation (session, transaction, GCK_OBJECT (cred), attrs, n_attrs);
+		return GCK_OBJECT (cred);
+	} else {
 		gck_transaction_fail (transaction, rv);
+		return NULL;
+	}
 }
 
 static void
diff --git a/pkcs11/gck/gck-dh-mechanism.c b/pkcs11/gck/gck-dh-mechanism.c
index c16e1da..54765ca 100644
--- a/pkcs11/gck/gck-dh-mechanism.c
+++ b/pkcs11/gck/gck-dh-mechanism.c
@@ -25,13 +25,58 @@
 #include "gck-crypto.h"
 #include "gck-dh-mechanism.h"
 #include "gck-dh-private-key.h"
-#include "gck-dh-public-key.h"
 #include "gck-session.h"
+#include "gck-transaction.h"
 
 #include "egg/egg-dh.h"
 #include "egg/egg-libgcrypt.h"
 #include "egg/egg-secure-memory.h"
 
+static GckObject*
+create_dh_object (GckSession *session, GckTransaction *transaction, CK_OBJECT_CLASS klass,
+                  CK_ATTRIBUTE_PTR value, CK_ATTRIBUTE_PTR prime, CK_ATTRIBUTE_PTR base,
+                  CK_ATTRIBUTE_PTR id, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	CK_KEY_TYPE type = CKK_DH;
+	CK_ATTRIBUTE attr;
+	GckObject *object;
+	GArray *array;
+
+	array = g_array_new (FALSE, TRUE, sizeof (CK_ATTRIBUTE));
+
+	/* Setup the value */
+	g_array_append_val (array, *value);
+
+	/* Add in the DH params */
+	g_array_append_val (array, *prime);
+	g_array_append_val (array, *base);
+
+	/* Setup the class */
+	attr.type = CKA_CLASS;
+	attr.pValue = &klass;
+	attr.ulValueLen = sizeof (klass);
+	g_array_append_val (array, attr);
+
+	/* Setup the key type */
+	attr.type = CKA_KEY_TYPE;
+	attr.pValue = &type;
+	attr.ulValueLen = sizeof (type);
+	g_array_append_val (array, attr);
+
+	/* All the other values */
+	g_array_append_vals (array, attrs, n_attrs);
+
+	/* Add in the identifier last */
+	g_array_append_val (array, *id);
+
+	/* Create the public key object */
+	object = gck_session_create_object_for_attributes (session, transaction,
+	                                                   (CK_ATTRIBUTE_PTR)array->data, array->len);
+
+	g_array_free (array, TRUE);
+	return object;
+}
+
 CK_RV
 gck_dh_mechanism_generate (GckSession *session, CK_ATTRIBUTE_PTR pub_atts,
                            CK_ULONG n_pub_atts, CK_ATTRIBUTE_PTR priv_atts,
@@ -43,28 +88,39 @@ gck_dh_mechanism_generate (GckSession *session, CK_ATTRIBUTE_PTR pub_atts,
 	gcry_mpi_t pub = NULL;
 	gcry_mpi_t priv = NULL;
 	gcry_error_t gcry;
-	guchar *buffer, *id;
-	gsize n_buffer, n_id;
-	GckManager *manager;
-	GckModule *module;
+	CK_ATTRIBUTE value, id;
+	CK_ATTRIBUTE_PTR aprime;
+	CK_ATTRIBUTE_PTR abase;
+	GckTransaction *transaction;
+	gboolean ret;
+	gsize length;
 	gulong bits;
+	CK_RV rv;
 
 	g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
 	g_return_val_if_fail (pub_key, CKR_GENERAL_ERROR);
 	g_return_val_if_fail (priv_key, CKR_GENERAL_ERROR);
 
-	if (!gck_attributes_find_mpi (pub_atts, n_pub_atts, CKA_PRIME, &prime) ||
-	    !gck_attributes_find_mpi (pub_atts, n_pub_atts, CKA_BASE, &base)) {
-		gcry_mpi_release (prime);
-		gcry_mpi_release (base);
+	*priv_key = NULL;
+	*pub_key = NULL;
+
+	aprime = gck_attributes_find (pub_atts, n_pub_atts, CKA_PRIME);
+	abase = gck_attributes_find (pub_atts, n_pub_atts, CKA_BASE);
+	if (!aprime || !abase)
 		return CKR_TEMPLATE_INCOMPLETE;
-	}
 
-	gck_attributes_consume (pub_atts, n_pub_atts, CKA_PRIME, CKA_BASE, G_MAXULONG);
+	rv = gck_attribute_get_mpi (aprime, &prime);
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = gck_attribute_get_mpi (abase, &base);
+	if (rv != CKR_OK) {
+		gcry_mpi_release (prime);
+		return rv;
+	}
 
 	if (!gck_attributes_find_ulong (priv_atts, n_priv_atts, CKA_VALUE_BITS, &bits))
 		bits = gcry_mpi_get_nbits (prime);
-
 	gck_attributes_consume (priv_atts, n_priv_atts, CKA_VALUE_BITS, G_MAXULONG);
 
 	/* The private key must be less than or equal to prime */
@@ -74,43 +130,73 @@ gck_dh_mechanism_generate (GckSession *session, CK_ATTRIBUTE_PTR pub_atts,
 		return CKR_TEMPLATE_INCONSISTENT;
 	}
 
-	if (!egg_dh_gen_pair (prime, base, bits, &priv, &pub)) {
-		gcry_mpi_release (prime);
-		gcry_mpi_release (base);
+	ret = egg_dh_gen_pair (prime, base, bits, &priv, &pub);
+
+	gcry_mpi_release (prime);
+	gcry_mpi_release (base);
+
+	if (ret == FALSE)
 		return CKR_FUNCTION_FAILED;
-	}
 
-	/* Write the public key out to raw data, so we can use it for an ID */
-	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_buffer, pub);
+	/* Write the public key out to raw data */
+	value.type = CKA_VALUE;
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &length, pub);
 	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
-	buffer = g_malloc (n_buffer);
-	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, n_buffer, &n_buffer, pub);
+	value.pValue = g_malloc (length);
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value.pValue, length, &length, pub);
 	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
-	if (n_buffer < 16) {
-		n_id = n_buffer;
-		id = g_memdup (buffer, n_id);
+	value.ulValueLen = length;
+
+	/* Create an identifier */
+	id.type = CKA_ID;
+	if (value.ulValueLen < 16) {
+		id.ulValueLen = value.ulValueLen;
+		id.pValue = g_memdup (value.pValue, value.ulValueLen);
 	} else {
-		n_id = 16;
-		id = g_memdup (buffer + (n_buffer - 16), n_id);
+		id.ulValueLen = 16;
+		id.pValue = g_memdup ((guchar*)value.pValue + (value.ulValueLen - 16), id.ulValueLen);
 	}
 
-	manager = gck_manager_for_template (pub_atts, n_pub_atts, session);
-	module = gck_session_get_module (session);
+	transaction = gck_transaction_new ();
+
+	*pub_key = create_dh_object (session, transaction, CKO_PUBLIC_KEY, &value,
+	                            aprime, abase, &id, pub_atts, n_pub_atts);
+	g_free (value.pValue);
+
+	if (!gck_transaction_get_failed (transaction)) {
 
-	*pub_key = GCK_OBJECT (gck_dh_public_key_new (module, manager, prime, base,
-	                                              pub, id, n_id));
+		/* Write the private key out to raw data */
+		value.type = CKA_VALUE;
+		gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &length, pub);
+		g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+		value.pValue = egg_secure_alloc (length);
+		gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value.pValue, length, &length, pub);
+		g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+		value.ulValueLen = length;
 
-	id = g_memdup (id, n_id);
-	prime = gcry_mpi_copy (prime);
-	base = gcry_mpi_copy (base);
+		*priv_key = create_dh_object (session, transaction, CKO_PRIVATE_KEY, &value,
+		                              aprime, abase, &id, priv_atts, n_priv_atts);
+		egg_secure_clear (value.pValue, value.ulValueLen);
+		egg_secure_free (value.pValue);
+	}
+
+	g_free (id.pValue);
 
-	*priv_key = GCK_OBJECT (gck_dh_private_key_new (module, manager, prime, base,
-	                                                priv, id, n_id));
+	gck_transaction_complete (transaction);
+	if (gck_transaction_get_failed (transaction)) {
+		if (*pub_key)
+			g_object_unref (*pub_key);
+		if (*priv_key)
+			g_object_unref (*priv_key);
+		*priv_key = *pub_key = NULL;
+	}
+
+	rv = gck_transaction_get_result (transaction);
+	g_object_unref (transaction);
 
 	gck_attributes_consume (pub_atts, n_pub_atts, CKA_PRIME, CKA_BASE, G_MAXULONG);
 
-	g_free (buffer);
-	return CKR_OK;
+	return rv;
 }
 
 static gpointer
@@ -163,7 +249,7 @@ gck_dh_mechanism_derive (GckSession *session, CK_MECHANISM_PTR mech, GckObject *
 	gboolean ret;
 	gsize n_value;
 	gpointer value;
-	CK_RV rv;
+	GckTransaction *transaction;
 
 	g_return_val_if_fail (GCK_IS_DH_PRIVATE_KEY (base), CKR_GENERAL_ERROR);
 
@@ -201,12 +287,14 @@ gck_dh_mechanism_derive (GckSession *session, CK_MECHANISM_PTR mech, GckObject *
 	/* Add the remainder of the attributes */
 	g_array_append_vals (array, attrs, n_attrs);
 
+	transaction = gck_transaction_new ();
+
 	/* Now create an object with these attributes */
-	rv = gck_session_create_object_for_attributes (session, (CK_ATTRIBUTE_PTR)array->data,
-	                                               array->len, derived);
+	*derived = gck_session_create_object_for_attributes (session, transaction,
+	                                                     (CK_ATTRIBUTE_PTR)array->data, array->len);
 
 	egg_secure_free (value);
 	g_array_free (array, TRUE);
 
-	return rv;
+	return gck_transaction_complete_and_unref (transaction);
 }
diff --git a/pkcs11/gck/gck-dh-private-key.c b/pkcs11/gck/gck-dh-private-key.c
index 4017275..72af177 100644
--- a/pkcs11/gck/gck-dh-private-key.c
+++ b/pkcs11/gck/gck-dh-private-key.c
@@ -42,15 +42,16 @@ G_DEFINE_TYPE (GckDhPrivateKey, gck_dh_private_key, GCK_TYPE_DH_KEY);
  * INTERNAL
  */
 
-static void
+static GckObject*
 factory_create_dh_private_key (GckSession *session, GckTransaction *transaction,
-                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckManager *manager;
 	gcry_mpi_t prime = NULL;
 	gcry_mpi_t base = NULL;
 	gcry_mpi_t value = NULL;
 	CK_ATTRIBUTE_PTR idattr;
+	GckObject *object;
 
 	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &prime) ||
 	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &base) ||
@@ -58,17 +59,21 @@ factory_create_dh_private_key (GckSession *session, GckTransaction *transaction,
 		gcry_mpi_release (prime);
 		gcry_mpi_release (base);
 		gcry_mpi_release (value);
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
 	}
 
 	manager = gck_manager_for_template (attrs, n_attrs, session);
 	idattr = gck_attributes_find (attrs, n_attrs, CKA_ID);
 
-	*object = GCK_OBJECT (gck_dh_private_key_new (gck_session_get_module (session),
-	                                             manager, prime, base, value,
-	                                             idattr ? g_memdup (idattr->pValue, idattr->ulValueLen) : NULL,
-	                                             idattr ? idattr->ulValueLen : 0));
+	object = GCK_OBJECT (gck_dh_private_key_new (gck_session_get_module (session),
+	                                            manager, prime, base, value,
+	                                            idattr ? g_memdup (idattr->pValue, idattr->ulValueLen) : NULL,
+	                                            idattr ? idattr->ulValueLen : 0));
 	gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_BASE, CKA_VALUE, G_MAXULONG);
+
+	gck_session_complete_object_creation (session, transaction, object, attrs, n_attrs);
+	return object;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/gck/gck-dh-public-key.c b/pkcs11/gck/gck-dh-public-key.c
index 41f7c40..d6f5284 100644
--- a/pkcs11/gck/gck-dh-public-key.c
+++ b/pkcs11/gck/gck-dh-public-key.c
@@ -42,15 +42,16 @@ G_DEFINE_TYPE (GckDhPublicKey, gck_dh_public_key, GCK_TYPE_DH_KEY);
  * INTERNAL
  */
 
-static void
+static GckObject*
 factory_create_dh_public_key (GckSession *session, GckTransaction *transaction,
-                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckManager *manager;
 	gcry_mpi_t prime = NULL;
 	gcry_mpi_t base = NULL;
 	gcry_mpi_t value = NULL;
 	CK_ATTRIBUTE_PTR idattr;
+	GckObject *object;
 
 	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &prime) ||
 	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &base) ||
@@ -58,17 +59,21 @@ factory_create_dh_public_key (GckSession *session, GckTransaction *transaction,
 		gcry_mpi_release (prime);
 		gcry_mpi_release (base);
 		gcry_mpi_release (value);
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
 	}
 
 	manager = gck_manager_for_template (attrs, n_attrs, session);
 	idattr = gck_attributes_find (attrs, n_attrs, CKA_ID);
 
-	*object = GCK_OBJECT (gck_dh_public_key_new (gck_session_get_module (session),
-	                                             manager, prime, base, value,
-	                                             idattr ? g_memdup (idattr->pValue, idattr->ulValueLen) : NULL,
-	                                             idattr ? idattr->ulValueLen : 0));
+	object = GCK_OBJECT (gck_dh_public_key_new (gck_session_get_module (session),
+	                                            manager, prime, base, value,
+	                                            idattr ? g_memdup (idattr->pValue, idattr->ulValueLen) : NULL,
+	                                            idattr ? idattr->ulValueLen : 0));
 	gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_BASE, CKA_VALUE, G_MAXULONG);
+
+	gck_session_complete_object_creation (session, transaction, object, attrs, n_attrs);
+	return object;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/gck/gck-factory.h b/pkcs11/gck/gck-factory.h
index 54a54d9..9570029 100644
--- a/pkcs11/gck/gck-factory.h
+++ b/pkcs11/gck/gck-factory.h
@@ -28,8 +28,8 @@
 
 #include "gck-types.h"
 
-typedef void (*GckFactoryFunc) (GckSession *session, GckTransaction *transaction,
-                                CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object);
+typedef GckObject* (*GckFactoryFunc) (GckSession *session, GckTransaction *transaction,
+                                      CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs);
 
 struct _GckFactory {
 	CK_ATTRIBUTE_PTR attrs;
diff --git a/pkcs11/gck/gck-private-xsa-key.c b/pkcs11/gck/gck-private-xsa-key.c
index 7b86b85..f099d2c 100644
--- a/pkcs11/gck/gck-private-xsa-key.c
+++ b/pkcs11/gck/gck-private-xsa-key.c
@@ -143,27 +143,28 @@ done:
 	return ret;
 }
 
-static void
+static GckObject*
 factory_create_private_xsa_key (GckSession *session, GckTransaction *transaction,
-                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckPrivateXsaKey *key;
 	GckSexp *sexp;
 
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (object);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	sexp = gck_private_xsa_key_create_sexp (session, transaction, attrs, n_attrs);
 	if (sexp == NULL)
-		return;
+		return NULL;
 
 	key = g_object_new (GCK_TYPE_PRIVATE_XSA_KEY, "base-sexp", sexp,
 	                    "module", gck_session_get_module (session),
 	                    "manager", gck_manager_for_template (attrs, n_attrs, session),
 	                    NULL);
 	key->pv->sexp = sexp;
-	*object = GCK_OBJECT (key);
+
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (key), attrs, n_attrs);
+	return GCK_OBJECT (key);
 }
 
 static gboolean
diff --git a/pkcs11/gck/gck-public-xsa-key.c b/pkcs11/gck/gck-public-xsa-key.c
index 5ab32bf..e6f3eb9 100644
--- a/pkcs11/gck/gck-public-xsa-key.c
+++ b/pkcs11/gck/gck-public-xsa-key.c
@@ -138,24 +138,27 @@ done:
 	return ret;
 }
 
-static void
+static GckObject*
 factory_create_public_xsa_key (GckSession *session, GckTransaction *transaction,
-                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
+	GckObject *object = NULL;
 	GckSexp *sexp;
 
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (object);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	sexp = gck_public_xsa_key_create_sexp (session, transaction, attrs, n_attrs);
 	if (sexp != NULL) {
-		*object = g_object_new (GCK_TYPE_PUBLIC_XSA_KEY, "base-sexp", sexp,
-		                        "module", gck_session_get_module (session),
-		                        "manager", gck_manager_for_template (attrs, n_attrs, session),
-		                        NULL);
+		object = g_object_new (GCK_TYPE_PUBLIC_XSA_KEY, "base-sexp", sexp,
+		                       "module", gck_session_get_module (session),
+		                       "manager", gck_manager_for_template (attrs, n_attrs, session),
+		                       NULL);
 		gck_sexp_unref (sexp);
+		gck_session_complete_object_creation (session, transaction, object, attrs, n_attrs);
 	}
+
+	return object;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index 87e8c76..e33adc5 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -377,52 +377,6 @@ attributes_find_boolean (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
 	return FALSE;
 }
 
-static void
-finish_up_object_creation (GckSession *self, GckObject *object, GckTransaction *transaction,
-                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
-{
-	gboolean is_private;
-	gulong i;
-
-	g_assert (GCK_IS_SESSION (self));
-	g_assert (GCK_IS_OBJECT (object));
-	g_assert (GCK_IS_TRANSACTION (transaction));
-	g_assert (!gck_transaction_get_failed (transaction));
-
-	gck_object_create_attributes (object, self, transaction, attrs, n_attrs);
-	if (gck_transaction_get_failed (transaction))
-		return;
-
-	/* See if we can create due to read-only */
-	if (gck_object_is_token (object)) {
-		if (!gck_object_is_transient (object) &&
-		    gck_module_get_write_protected (self->pv->module))
-			return gck_transaction_fail (transaction, CKR_TOKEN_WRITE_PROTECTED);
-		else if (self->pv->read_only)
-			return gck_transaction_fail (transaction, CKR_SESSION_READ_ONLY);
-	}
-
-	/* Can only create public objects unless logged in */
-	if (gck_session_get_logged_in (self) != CKU_USER &&
-	    gck_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private) && 
-	    is_private == TRUE) {
-		return gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
-	}
-
-	/* Find somewhere to store the object */
-	if (gck_object_is_token (object))
-		gck_module_store_token_object (self->pv->module, transaction, object); 
-	else
-		add_object (self, transaction, object);
-
-	/* Next go through and set all attributes that weren't used initially */
-	gck_attributes_consume (attrs, n_attrs, CKA_TOKEN, G_MAXULONG);
-	for (i = 0; i < n_attrs && !gck_transaction_get_failed (transaction); ++i) {
-		if (!gck_attribute_consumed (&attrs[i]))
-			gck_object_set_attribute (object, self, transaction, &attrs[i]);
-	}
-}
-
 /* -----------------------------------------------------------------------------
  * OBJECT 
  */
@@ -859,21 +813,24 @@ gck_session_for_each_credential (GckSession *self, GckObject *object,
 	return (l != NULL);
 }
 
-CK_RV
+GckObject*
 gck_session_create_object_for_factory (GckSession *self, GckFactory *factory,
-                                       CK_ATTRIBUTE_PTR template, CK_ULONG count,
-                                       GckObject **object)
+                                       GckTransaction *transaction,
+                                       CK_ATTRIBUTE_PTR template, CK_ULONG count)
 {
-	GckTransaction *transaction;
-	CK_RV rv;
+	GckTransaction *owned = NULL;
+	GckObject  *object;
+	gulong i;
 
-	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_GENERAL_ERROR);
-	g_return_val_if_fail (factory && factory->func, CKR_GENERAL_ERROR);
-	g_return_val_if_fail (template || !count, CKR_GENERAL_ERROR);
-	g_return_val_if_fail (object, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
+	g_return_val_if_fail (factory && factory->func, NULL);
+	g_return_val_if_fail (template || !count, NULL);
 
 	/* The transaction for this whole dealio */
-	transaction = gck_transaction_new ();
+	if (!transaction)
+		owned = transaction = gck_transaction_new ();
+
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
 
 	/*
 	 * Duplicate the memory for the attributes (but not values) so we
@@ -882,43 +839,94 @@ gck_session_create_object_for_factory (GckSession *self, GckFactory *factory,
 	template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
 
 	/* Actually create the object */
-	*object = NULL;
-	(factory->func) (self, transaction, template, count, object);
+	object = (factory->func) (self, transaction, template, count);
 
-	/* Complete creation, and do storage */
-	if (!gck_transaction_get_failed (transaction)) {
-		g_return_val_if_fail (*object, CKR_GENERAL_ERROR);
-		finish_up_object_creation (self, *object, transaction, template, count);
+	/* A NULL result without a failure code, bad */
+	if (object == NULL && !gck_transaction_get_failed (transaction)) {
+		g_warn_if_reached ();
+		gck_transaction_fail (transaction, CKR_GENERAL_ERROR);
+	}
+
+	/* Next go through and set all attributes that weren't used initially */
+	gck_attributes_consume (template, count, CKA_TOKEN, G_MAXULONG);
+	for (i = 0; i < count && !gck_transaction_get_failed (transaction); ++i) {
+		if (!gck_attribute_consumed (&template[i]))
+			gck_object_set_attribute (object, self, transaction, &template[i]);
 	}
 
 	g_free (template);
 
-	gck_transaction_complete (transaction);
-	rv = gck_transaction_get_result (transaction);
-	g_object_unref (transaction);
+	if (owned)
+		gck_transaction_complete (transaction);
 
-	if (*object)
-		g_object_unref (*object);
-	if (rv != CKR_OK)
-		*object = NULL;
+	/* Object is owned by module or session */
+	if (gck_transaction_get_failed (transaction)) {
+		if (object)
+			g_object_unref (object);
+		object = NULL;
+	}
 
-	return rv;
+	if (owned)
+		g_object_unref (owned);
+
+	return object;
 }
 
-CK_RV
-gck_session_create_object_for_attributes (GckSession *self, CK_ATTRIBUTE_PTR attrs,
-                                          CK_ULONG n_attrs, GckObject **object)
+GckObject*
+gck_session_create_object_for_attributes (GckSession *self, GckTransaction *transaction,
+                                          CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckFactory *factory;
 
-	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
 
 	/* Find out if we can create such an object */
 	factory = gck_module_find_factory (gck_session_get_module (self), attrs, n_attrs);
-	if (factory == NULL)
-		return CKR_TEMPLATE_INCOMPLETE;
+	if (factory == NULL) {
+		if (transaction)
+			gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
 
-	return gck_session_create_object_for_factory (self, factory, attrs, n_attrs, object);
+	return gck_session_create_object_for_factory (self, factory, transaction, attrs, n_attrs);
+}
+
+void
+gck_session_complete_object_creation (GckSession *self, GckTransaction *transaction,
+                                      GckObject *object, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	gboolean is_private;
+
+	g_return_if_fail (GCK_IS_SESSION (self));
+	g_return_if_fail (GCK_IS_OBJECT (object));
+	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+	g_return_if_fail (!gck_transaction_get_failed (transaction));
+
+	gck_object_create_attributes (object, self, transaction, attrs, n_attrs);
+	if (gck_transaction_get_failed (transaction))
+		return;
+
+	/* See if we can create due to read-only */
+	if (gck_object_is_token (object)) {
+		if (!gck_object_is_transient (object) &&
+		    gck_module_get_write_protected (self->pv->module))
+			return gck_transaction_fail (transaction, CKR_TOKEN_WRITE_PROTECTED);
+		else if (self->pv->read_only)
+			return gck_transaction_fail (transaction, CKR_SESSION_READ_ONLY);
+	}
+
+	/* Can only create public objects unless logged in */
+	if (gck_session_get_logged_in (self) != CKU_USER &&
+	    gck_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private) &&
+	    is_private == TRUE) {
+		return gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
+	}
+
+	/* Find somewhere to store the object */
+	if (gck_object_is_token (object))
+		gck_module_store_token_object (self->pv->module, transaction, object);
+	else
+		add_object (self, transaction, object);
 }
 
 /* -----------------------------------------------------------------------------
@@ -983,6 +991,7 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
                             CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
 {
 	GckObject *object = NULL;
+	GckTransaction *transaction;
 	CK_RV rv;
 
 	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
@@ -991,10 +1000,16 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
 	if (!(!count || template))
 		return CKR_ARGUMENTS_BAD;
 
-	rv = gck_session_create_object_for_attributes (self, template, count, &object);
+	transaction = gck_transaction_new ();
+
+	object = gck_session_create_object_for_attributes (self, transaction, template, count);
+
+	rv = gck_transaction_complete_and_unref (transaction);
+
 	if (rv == CKR_OK) {
 		g_assert (object);
 		*new_object = gck_object_get_handle (object);
+		g_object_unref (object);
 	}
 
 	return rv;
@@ -1508,11 +1523,6 @@ gck_session_C_GenerateKeyPair (GckSession* self, CK_MECHANISM_PTR mechanism,
 	if (rv != CKR_OK)
 		gck_transaction_fail (transaction, rv);
 
-	if (!gck_transaction_get_failed (transaction))
-		finish_up_object_creation (self, pub, transaction, pub_template, pub_count);
-	if (!gck_transaction_get_failed (transaction))
-		finish_up_object_creation (self, priv, transaction, priv_template, priv_count);
-
 	g_free (pub_template);
 	g_free (priv_template);
 
@@ -1562,7 +1572,7 @@ gck_session_C_WrapKey (GckSession* self, CK_MECHANISM_PTR mechanism,
 		return rv;
 
 	return gck_crypto_wrap_key (self, mechanism, wrapper, wrapped,
-	                              wrapped_key, wrapped_key_len);
+	                            wrapped_key, wrapped_key_len);
 }
 
 CK_RV
@@ -1600,8 +1610,10 @@ gck_session_C_UnwrapKey (GckSession* self, CK_MECHANISM_PTR mechanism,
 
 	g_free (template);
 
-	if (rv == CKR_OK)
+	if (rv == CKR_OK) {
 		*key = gck_object_get_handle (unwrapped);
+		g_object_unref (unwrapped);
+	}
 
 	return rv;
 }
@@ -1638,8 +1650,10 @@ gck_session_C_DeriveKey (GckSession* self, CK_MECHANISM_PTR mechanism,
 
 	g_free (template);
 
-	if (rv == CKR_OK)
+	if (rv == CKR_OK) {
 		*key = gck_object_get_handle (derived);
+		g_object_unref (derived);
+	}
 
 	return rv;
 }
diff --git a/pkcs11/gck/gck-session.h b/pkcs11/gck/gck-session.h
index 6904509..348c312 100644
--- a/pkcs11/gck/gck-session.h
+++ b/pkcs11/gck/gck-session.h
@@ -110,16 +110,22 @@ gboolean                 gck_session_for_each_credential                (GckSess
                                                                          GckCredentialFunc func,
                                                                          gpointer user_data);
 
-CK_RV                    gck_session_create_object_for_factory          (GckSession *self,
+GckObject*               gck_session_create_object_for_factory          (GckSession *self,
                                                                          GckFactory *factory,
+                                                                         GckTransaction *transaction,
+                                                                         CK_ATTRIBUTE_PTR attrs,
+                                                                         CK_ULONG n_attrs);
+
+GckObject*               gck_session_create_object_for_attributes       (GckSession *self,
+                                                                         GckTransaction *transaction,
                                                                          CK_ATTRIBUTE_PTR attrs,
-                                                                         CK_ULONG n_attrs,
-                                                                         GckObject **object);
+                                                                         CK_ULONG n_attrs);
 
-CK_RV                    gck_session_create_object_for_attributes       (GckSession *self,
+void                     gck_session_complete_object_creation           (GckSession *self,
+                                                                         GckTransaction *transaction,
+                                                                         GckObject *object,
                                                                          CK_ATTRIBUTE_PTR attrs,
-                                                                         CK_ULONG n_attrs,
-                                                                         GckObject **object);
+                                                                         CK_ULONG n_attrs);
 
 CK_RV                    gck_session_C_GetFunctionStatus                (GckSession *self);
 
diff --git a/pkcs11/gck/gck-transaction.c b/pkcs11/gck/gck-transaction.c
index bab4733..f848793 100644
--- a/pkcs11/gck/gck-transaction.c
+++ b/pkcs11/gck/gck-transaction.c
@@ -494,3 +494,17 @@ gck_transaction_remove_file (GckTransaction *self, const gchar *filename)
 		gck_transaction_fail (self, CKR_DEVICE_ERROR);
 	}
 }
+
+CK_RV
+gck_transaction_complete_and_unref (GckTransaction *self)
+{
+	CK_RV rv;
+
+	g_return_val_if_fail (GCK_IS_TRANSACTION (self), CKR_GENERAL_ERROR);
+
+	gck_transaction_complete (self);
+	rv = gck_transaction_get_result (self);
+	g_object_unref (self);
+
+	return rv;
+}
diff --git a/pkcs11/gck/gck-transaction.h b/pkcs11/gck/gck-transaction.h
index b065ac3..481c189 100644
--- a/pkcs11/gck/gck-transaction.h
+++ b/pkcs11/gck/gck-transaction.h
@@ -77,4 +77,6 @@ void                        gck_transaction_write_file             (GckTransacti
 void                        gck_transaction_remove_file            (GckTransaction *self,
                                                                     const gchar *filename);
 
+CK_RV                       gck_transaction_complete_and_unref     (GckTransaction *self);
+
 #endif /* __GCK_TRANSACTION_H__ */
diff --git a/pkcs11/gck/tests/test-module.c b/pkcs11/gck/tests/test-module.c
index b3abe7d..a506ed7 100644
--- a/pkcs11/gck/tests/test-module.c
+++ b/pkcs11/gck/tests/test-module.c
@@ -91,11 +91,10 @@ test_module_open_session (gboolean writable)
 GckObject*
 test_module_object_new (GckSession *session)
 {
-	GckObject *object;
-
 	CK_BBOOL token = CK_FALSE;
 	CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
 	CK_CERTIFICATE_TYPE type = CKC_X_509;
+	GckObject *object;
 
 	gsize n_data;
 	guchar *data = test_data_read ("test-certificate-1.der", &n_data);
@@ -107,9 +106,9 @@ test_module_object_new (GckSession *session)
 		{ CKA_VALUE, data, n_data },
 	};
 
-	if (gck_session_create_object_for_factory (session, GCK_FACTORY_CERTIFICATE,
-	                                           attrs, G_N_ELEMENTS (attrs), &object) == CKR_OK)
-		return object;
-
-	return NULL;
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_CERTIFICATE, NULL,
+	                                              attrs, G_N_ELEMENTS (attrs));
+	if (object) /* Owned by storage */
+		g_object_unref (object);
+	return object;
 }
diff --git a/pkcs11/secret-store/gck-secret-collection.c b/pkcs11/secret-store/gck-secret-collection.c
index 8bb0e4c..03d826a 100644
--- a/pkcs11/secret-store/gck-secret-collection.c
+++ b/pkcs11/secret-store/gck-secret-collection.c
@@ -217,9 +217,9 @@ remove_item (GckSecretCollection *self, GckTransaction *transaction, GckSecretIt
 	g_object_unref (item);
 }
 
-static void
+static GckObject*
 factory_create_collection (GckSession *session, GckTransaction *transaction,
-                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **result)
+                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckSecretCollection *collection = NULL;
 	CK_OBJECT_HANDLE handle;
@@ -228,37 +228,40 @@ factory_create_collection (GckSession *session, GckTransaction *transaction,
 	gchar *identifier = NULL;
 	GckSecretData *sdata;
 	gchar *label = NULL;
-	gboolean is_token;
 	GckCredential *cred;
 	GckObject *object;
 	CK_RV rv;
 
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (result);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
-	if (!gck_attributes_find_boolean (attrs, n_attrs, CKA_TOKEN, &is_token))
-		is_token = FALSE;
-	if (is_token)
-		manager = gck_module_get_manager (gck_session_get_module (session));
-	else
-		manager = gck_session_get_manager (session);
+	manager = gck_manager_for_template (attrs, n_attrs, session);
 
 	/* Must have a credential, which is not associated with an object yet */
-	if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_G_CREDENTIAL, &handle))
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
-	if (gck_session_lookup_readable_object (session, handle, &object) != CKR_OK)
-		return gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_G_CREDENTIAL, &handle)) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
+
+	if (gck_session_lookup_readable_object (session, handle, &object) != CKR_OK) {
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+		return NULL;
+	}
+
 	cred = GCK_CREDENTIAL (object);
-	if (gck_credential_get_object (cred) != NULL)
-		return gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	if (gck_credential_get_object (cred) != NULL) {
+		gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+		return NULL;
+	}
 
 	/* See if a collection attribute was specified, not present means all collections */
 	attr = gck_attributes_find (attrs, n_attrs, CKA_LABEL);
 	if (attr != NULL) {
 		rv = gck_attribute_get_string (attr, &label);
-		if (rv != CKR_OK)
-			return gck_transaction_fail (transaction, rv);
+		if (rv != CKR_OK) {
+			gck_transaction_fail (transaction, rv);
+			return NULL;
+		}
 		identifier = g_utf8_strdown (label, -1);
 		g_strdelimit (identifier, ":/\\<>|\t\n\r\v ", '_');
 		gck_attribute_consume (attr);
@@ -285,7 +288,8 @@ factory_create_collection (GckSession *session, GckTransaction *transaction,
 	gck_secret_data_set_master (sdata, gck_credential_get_secret (cred));
 	track_secret_data (collection, sdata);
 
-	*result = GCK_OBJECT (collection);
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (collection), attrs, n_attrs);
+	return GCK_OBJECT (collection);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/secret-store/gck-secret-item.c b/pkcs11/secret-store/gck-secret-item.c
index 48e1efa..704177c 100644
--- a/pkcs11/secret-store/gck-secret-item.c
+++ b/pkcs11/secret-store/gck-secret-item.c
@@ -97,9 +97,9 @@ begin_set_fields (GckSecretItem *self, GckTransaction *transaction, GHashTable *
 	self->fields = fields;
 }
 
-static void
+static GckObject*
 factory_create_item (GckSession *session, GckTransaction *transaction,
-                     CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **result)
+                     CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckSecretCollection *collection = NULL;
 	GckSecretItem *item;
@@ -108,14 +108,15 @@ factory_create_item (GckSession *session, GckTransaction *transaction,
 	CK_ATTRIBUTE *attr;
 	gboolean is_token;
 
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (result);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	/* See if a collection attribute was specified */
 	attr = gck_attributes_find (attrs, n_attrs, CKA_G_COLLECTION);
-	if (attr == NULL)
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+	if (attr == NULL) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
 
 	m_manager = gck_module_get_manager (gck_session_get_module (session));
 	s_manager = gck_session_get_manager (session);
@@ -128,14 +129,15 @@ factory_create_item (GckSession *session, GckTransaction *transaction,
 	else
 		collection = gck_secret_collection_find (attr, s_manager, NULL);
 
-	if (!collection)
-		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+	if (!collection) {
+		gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+		return NULL;
+	}
 
-	/* The collection owns the item */
+	/* Create a new collection which will own the item */
 	item = gck_secret_collection_create_item (collection, transaction);
-
-	/* All the other fields are set later ... */
-	*result = g_object_ref (item);
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (item), attrs, n_attrs);
+	return g_object_ref (item);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/secret-store/gck-secret-search.c b/pkcs11/secret-store/gck-secret-search.c
index d177520..1315687 100644
--- a/pkcs11/secret-store/gck-secret-search.c
+++ b/pkcs11/secret-store/gck-secret-search.c
@@ -181,9 +181,9 @@ populate_search_from_manager (GckSecretSearch *self, GckManager *manager)
 	g_signal_connect (manager, "attribute-changed", G_CALLBACK (on_manager_changed_object), self);
 }
 
-static void
+static GckObject*
 factory_create_search (GckSession *session, GckTransaction *transaction,
-                       CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **result)
+                       CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckSecretCollection *collection = NULL;
 	GckManager *s_manager, *m_manager;
@@ -193,15 +193,14 @@ factory_create_search (GckSession *session, GckTransaction *transaction,
 	GckModule *module;
 	CK_RV rv;
 
-	g_return_if_fail (GCK_IS_TRANSACTION (transaction));
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (result);
+	g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	/* Find the fields being requested */
 	attr = gck_attributes_find (attrs, n_attrs, CKA_G_FIELDS);
 	if (attr == NULL) {
 		gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
-		return;
+		return NULL;
 	}
 
 	/* Parse the fields, into our internal representation */
@@ -209,7 +208,7 @@ factory_create_search (GckSession *session, GckTransaction *transaction,
 	gck_attribute_consume (attr);
 	if (rv != CKR_OK) {
 		gck_transaction_fail (transaction, rv);
-		return;
+		return NULL;
 	}
 
 	s_manager = gck_session_get_manager (session);
@@ -224,7 +223,7 @@ factory_create_search (GckSession *session, GckTransaction *transaction,
 		if (!collection) {
 			g_hash_table_unref (fields);
 			gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
-			return;
+			return NULL;
 		}
 	}
 
@@ -240,7 +239,9 @@ factory_create_search (GckSession *session, GckTransaction *transaction,
 
 	populate_search_from_manager (search, s_manager);
 	populate_search_from_manager (search, m_manager);
-	*result = GCK_OBJECT (search);
+
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (search), attrs, n_attrs);
+	return GCK_OBJECT (search);
 }
 
 static void
diff --git a/pkcs11/secret-store/tests/unit-test-secret-collection.c b/pkcs11/secret-store/tests/unit-test-secret-collection.c
index d6d96d5..9c8136c 100644
--- a/pkcs11/secret-store/tests/unit-test-secret-collection.c
+++ b/pkcs11/secret-store/tests/unit-test-secret-collection.c
@@ -52,7 +52,6 @@ DEFINE_SETUP(secret_collection)
 {
 	CK_OBJECT_CLASS klass = CKO_G_CREDENTIAL;
 	GckObject *cred;
-	CK_RV rv;
 
 	CK_ATTRIBUTE attrs[] = {
 		{ CKA_CLASS, &klass, sizeof (klass) },
@@ -69,15 +68,17 @@ DEFINE_SETUP(secret_collection)
 	g_assert (GCK_IS_SECRET_COLLECTION (collection));
 
 	/* Make two credentials */
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_CREDENTIAL,
-	                                            attrs, G_N_ELEMENTS (attrs), &cred);
-	g_assert (rv == CKR_OK);
+	cred = gck_session_create_object_for_factory (session, GCK_FACTORY_CREDENTIAL, NULL,
+	                                            attrs, G_N_ELEMENTS (attrs));
+	g_assert (cred != NULL);
 	credential = gck_object_get_handle (GCK_OBJECT (cred));
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_CREDENTIAL,
-	                                            attrs, G_N_ELEMENTS (attrs), &cred);
-	g_assert (rv == CKR_OK);
-	credential2 = gck_object_get_handle (GCK_OBJECT (cred));
+	g_object_unref (cred);
 
+	cred = gck_session_create_object_for_factory (session, GCK_FACTORY_CREDENTIAL, NULL,
+	                                            attrs, G_N_ELEMENTS (attrs));
+	g_assert (cred != NULL);
+	credential2 = gck_object_get_handle (GCK_OBJECT (cred));
+	g_object_unref (cred);
 }
 
 DEFINE_TEARDOWN(secret_collection)
@@ -349,7 +350,6 @@ DEFINE_TEST(secret_collection_factory)
 {
 	CK_OBJECT_CLASS klass = CKO_G_COLLECTION;
 	GckObject *object;
-	CK_RV rv;
 
 	CK_ATTRIBUTE attrs[] = {
 		{ CKA_CLASS, &klass, sizeof (klass) },
@@ -357,12 +357,13 @@ DEFINE_TEST(secret_collection_factory)
 		{ CKA_G_CREDENTIAL, &credential, sizeof (credential) },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            attrs, G_N_ELEMENTS (attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                attrs, G_N_ELEMENTS (attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
 
 	g_assert_cmpstr (gck_secret_object_get_label (GCK_SECRET_OBJECT (object)), ==, "blah");
+	g_object_unref (object);
 }
 
 DEFINE_TEST(secret_collection_factory_unnamed)
@@ -370,20 +371,20 @@ DEFINE_TEST(secret_collection_factory_unnamed)
 	CK_OBJECT_CLASS klass = CKO_G_COLLECTION;
 	const gchar *identifier;
 	GckObject *object;
-	CK_RV rv;
 
 	CK_ATTRIBUTE attrs[] = {
 		{ CKA_CLASS, &klass, sizeof (klass) },
 		{ CKA_G_CREDENTIAL, &credential, sizeof (credential) },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            attrs, G_N_ELEMENTS (attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                attrs, G_N_ELEMENTS (attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
 
 	identifier = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (object));
 	g_assert_cmpstr (identifier, !=, "");
+	g_object_unref (object);
 }
 
 DEFINE_TEST(secret_collection_factory_token)
@@ -392,7 +393,6 @@ DEFINE_TEST(secret_collection_factory_token)
 	const gchar *identifier;
 	GckObject *object;
 	CK_BBOOL token = CK_TRUE;
-	CK_RV rv;
 
 	CK_ATTRIBUTE attrs[] = {
 		{ CKA_CLASS, &klass, sizeof (klass) },
@@ -401,13 +401,14 @@ DEFINE_TEST(secret_collection_factory_token)
 		{ CKA_G_CREDENTIAL, &credential, sizeof (credential) },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            attrs, G_N_ELEMENTS (attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                attrs, G_N_ELEMENTS (attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
 
 	identifier = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (object));
 	g_assert (strstr (identifier, "blah"));
+	g_object_unref (object);
 }
 
 DEFINE_TEST(secret_collection_factory_duplicate)
@@ -415,7 +416,6 @@ DEFINE_TEST(secret_collection_factory_duplicate)
 	CK_OBJECT_CLASS klass = CKO_G_COLLECTION;
 	const gchar *identifier1, *identifier2;
 	GckObject *object;
-	CK_RV rv;
 
 	CK_ATTRIBUTE attrs[] = {
 		{ CKA_G_CREDENTIAL, &credential, sizeof (credential) },
@@ -423,23 +423,25 @@ DEFINE_TEST(secret_collection_factory_duplicate)
 		{ CKA_LABEL, "blah", 4 },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            attrs, G_N_ELEMENTS (attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                attrs, G_N_ELEMENTS (attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
 
 	identifier1 = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (object));
 	g_assert (strstr (identifier1, "blah"));
+	g_object_unref (object);
 
 	/* Use second credential for second object */
 	attrs[0].pValue = &credential2;
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            attrs, G_N_ELEMENTS (attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                attrs, G_N_ELEMENTS (attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
 
 	identifier2 = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (object));
 	g_assert (strstr (identifier2, "blah"));
+	g_object_unref (object);
 
 	g_assert_cmpstr (identifier1, !=, identifier2);
 }
@@ -451,7 +453,6 @@ DEFINE_TEST(secret_collection_factory_item)
 	const gchar *identifier;
 	GckObject *object;
 	CK_BBOOL token = CK_TRUE;
-	CK_RV rv;
 
 	CK_ATTRIBUTE c_attrs[] = {
 		{ CKA_CLASS, &c_klass, sizeof (c_klass) },
@@ -467,18 +468,20 @@ DEFINE_TEST(secret_collection_factory_item)
 		{ CKA_LABEL, "Item", 4 },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            c_attrs, G_N_ELEMENTS (c_attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                c_attrs, G_N_ELEMENTS (c_attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
-
 	identifier = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (object));
+	g_object_unref (object);
+
 	i_attrs[0].pValue = (gpointer)identifier;
 	i_attrs[0].ulValueLen = strlen (identifier);
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_ITEM,
-	                                            i_attrs, G_N_ELEMENTS (i_attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_ITEM, NULL,
+	                                                i_attrs, G_N_ELEMENTS (i_attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_ITEM (object));
+	g_object_unref (object);
 }
 
 DEFINE_TEST(secret_collection_token_remove)
@@ -487,7 +490,6 @@ DEFINE_TEST(secret_collection_token_remove)
 	GckTransaction *transaction;
 	GckObject *object;
 	CK_BBOOL token = CK_TRUE;
-	CK_RV rv;
 
 	CK_ATTRIBUTE attrs[] = {
 		{ CKA_CLASS, &klass, sizeof (klass) },
@@ -496,9 +498,9 @@ DEFINE_TEST(secret_collection_token_remove)
 		{ CKA_G_CREDENTIAL, &credential, sizeof (credential) },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            attrs, G_N_ELEMENTS (attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                attrs, G_N_ELEMENTS (attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
 
 	transaction = gck_transaction_new ();
@@ -506,6 +508,7 @@ DEFINE_TEST(secret_collection_token_remove)
 	g_assert (!gck_transaction_get_failed (transaction));
 	gck_transaction_complete (transaction);
 	g_object_unref (transaction);
+	g_object_unref (object);
 }
 
 DEFINE_TEST(secret_collection_token_item_remove)
@@ -516,7 +519,6 @@ DEFINE_TEST(secret_collection_token_item_remove)
 	const gchar *identifier;
 	GckObject *object;
 	CK_BBOOL token = CK_TRUE;
-	CK_RV rv;
 
 	CK_ATTRIBUTE c_attrs[] = {
 		{ CKA_CLASS, &c_klass, sizeof (c_klass) },
@@ -532,17 +534,18 @@ DEFINE_TEST(secret_collection_token_item_remove)
 		{ CKA_LABEL, "Item", 4 },
 	};
 
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION,
-	                                            c_attrs, G_N_ELEMENTS (c_attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_COLLECTION, NULL,
+	                                                c_attrs, G_N_ELEMENTS (c_attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_COLLECTION (object));
-
 	identifier = gck_secret_object_get_identifier (GCK_SECRET_OBJECT (object));
+	g_object_unref (object);
+
 	i_attrs[0].pValue = (gpointer)identifier;
 	i_attrs[0].ulValueLen = strlen (identifier);
-	rv = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_ITEM,
-	                                            i_attrs, G_N_ELEMENTS (i_attrs), &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, GCK_FACTORY_SECRET_ITEM, NULL,
+	                                                i_attrs, G_N_ELEMENTS (i_attrs));
+	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_ITEM (object));
 
 	transaction = gck_transaction_new ();
@@ -550,4 +553,5 @@ DEFINE_TEST(secret_collection_token_item_remove)
 	g_assert (!gck_transaction_get_failed (transaction));
 	gck_transaction_complete (transaction);
 	g_object_unref (transaction);
+	g_object_unref (object);
 }
diff --git a/pkcs11/secret-store/tests/unit-test-secret-search.c b/pkcs11/secret-store/tests/unit-test-secret-search.c
index 8a51591..1f1be89 100644
--- a/pkcs11/secret-store/tests/unit-test-secret-search.c
+++ b/pkcs11/secret-store/tests/unit-test-secret-search.c
@@ -87,10 +87,10 @@ DEFINE_TEST(create_search_incomplete)
 {
 	CK_ATTRIBUTE attrs[1];
 	GckObject *object = NULL;
-	CK_RV rv; 
+	GckTransaction *transaction = gck_transaction_new ();
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 0, &object);
-	g_assert (rv == CKR_TEMPLATE_INCOMPLETE);
+	object = gck_session_create_object_for_factory (session, factory, transaction, attrs, 0);
+	g_assert (gck_transaction_complete_and_unref (transaction) == CKR_TEMPLATE_INCOMPLETE);
 	g_assert (object == NULL);
 }
 
@@ -101,10 +101,10 @@ DEFINE_TEST(create_search_bad_fields)
 	};
 
 	GckObject *object = NULL;
-	CK_RV rv;
+	GckTransaction *transaction = gck_transaction_new ();
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 1, &object);
-	g_assert (rv == CKR_ATTRIBUTE_VALUE_INVALID);
+	object = gck_session_create_object_for_factory (session, factory, transaction, attrs, 1);
+	g_assert (gck_transaction_complete_and_unref (transaction) == CKR_ATTRIBUTE_VALUE_INVALID);
 	g_assert (object == NULL);
 }
 
@@ -121,21 +121,17 @@ DEFINE_TEST(create_search)
 	gulong vulong;
 	gboolean vbool;
 	gsize vsize;
-	CK_RV rv;
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 1, &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, factory, NULL, attrs, 1);
 	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_SEARCH (object));
 
 	if (!gck_object_get_attribute_ulong (object, session, CKA_CLASS, &vulong))
 		g_assert_not_reached ();
-	g_assert (rv == CKR_OK);
 	g_assert (vulong == CKO_G_SEARCH);
 
 	if (!gck_object_get_attribute_boolean (object, session, CKA_MODIFIABLE, &vbool))
 		g_assert_not_reached ();
-	g_assert (rv == CKR_OK);
 	g_assert (vbool == CK_TRUE);
 
 	vdata = gck_object_get_attribute_data (object, session, CKA_G_FIELDS, &vsize);
@@ -162,6 +158,8 @@ DEFINE_TEST(create_search)
 	/* No collection */
 	collection = gck_secret_search_get_collection (GCK_SECRET_SEARCH (object));
 	g_assert (collection == NULL);
+
+	g_object_unref (object);
 }
 
 DEFINE_TEST(create_search_and_match)
@@ -173,10 +171,8 @@ DEFINE_TEST(create_search_and_match)
 	GckObject *object = NULL;
 	gpointer vdata;
 	gsize vsize;
-	CK_RV rv;
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 1, &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, factory, NULL, attrs, 1);
 	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_SEARCH (object));
 
@@ -186,6 +182,8 @@ DEFINE_TEST(create_search_and_match)
 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gck_object_get_handle (GCK_OBJECT (item)));
 	g_free (vdata);
+
+	g_object_unref (object);
 }
 
 DEFINE_TEST(create_search_and_change_to_match)
@@ -198,15 +196,13 @@ DEFINE_TEST(create_search_and_change_to_match)
 	GHashTable *fields;
 	gpointer vdata;
 	gsize vsize;
-	CK_RV rv;
 
 	/* Make it not match */
 	fields = gck_secret_fields_new ();
 	gck_secret_item_set_fields (item, fields);
 	g_hash_table_unref (fields);
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 1, &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, factory, NULL, attrs, 1);
 	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_SEARCH (object));
 
@@ -228,6 +224,8 @@ DEFINE_TEST(create_search_and_change_to_match)
 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gck_object_get_handle (GCK_OBJECT (item)));
 	g_free (vdata);
+
+	g_object_unref (object);
 }
 
 DEFINE_TEST(create_search_and_change_to_not_match)
@@ -240,10 +238,8 @@ DEFINE_TEST(create_search_and_change_to_not_match)
 	GHashTable *fields;
 	gpointer vdata;
 	gsize vsize;
-	CK_RV rv;
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 1, &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, factory, NULL, attrs, 1);
 	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_SEARCH (object));
 
@@ -263,6 +259,8 @@ DEFINE_TEST(create_search_and_change_to_not_match)
 	vdata = gck_object_get_attribute_data (object, session, CKA_G_MATCHED, &vsize);
 	g_assert (vsize == 0);
 	g_free (vdata);
+
+	g_object_unref (object);
 }
 
 DEFINE_TEST(create_search_for_bad_collection)
@@ -273,10 +271,10 @@ DEFINE_TEST(create_search_for_bad_collection)
 	};
 
 	GckObject *object = NULL;
-	CK_RV rv;
+	GckTransaction *transaction = gck_transaction_new ();
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 2, &object);
-	g_assert (rv == CKR_TEMPLATE_INCONSISTENT);
+	object = gck_session_create_object_for_factory (session, factory, transaction, attrs, 2);
+	g_assert (gck_transaction_complete_and_unref (transaction) == CKR_TEMPLATE_INCONSISTENT);
 }
 
 DEFINE_TEST(create_search_for_collection)
@@ -289,10 +287,8 @@ DEFINE_TEST(create_search_for_collection)
 	GckObject *object = NULL;
 	gpointer vdata;
 	gsize vsize;
-	CK_RV rv;
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 2, &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, factory, NULL, attrs, 2);
 	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_SEARCH (object));
 
@@ -309,6 +305,8 @@ DEFINE_TEST(create_search_for_collection)
 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gck_object_get_handle (GCK_OBJECT (item)));
 	g_free (vdata);
+
+	g_object_unref (object);
 }
 
 DEFINE_TEST(create_search_for_collection_no_match)
@@ -324,7 +322,6 @@ DEFINE_TEST(create_search_for_collection_no_match)
 	GHashTable *fields;
 	gpointer vdata;
 	gsize vsize;
-	CK_RV rv;
 
 	ocoll = g_object_new (GCK_TYPE_SECRET_COLLECTION,
 	                      "module", module,
@@ -340,8 +337,7 @@ DEFINE_TEST(create_search_for_collection_no_match)
 	gck_secret_item_set_fields (oitem, fields);
 	g_hash_table_unref (fields);
 
-	rv = gck_session_create_object_for_factory (session, factory, attrs, 2, &object);
-	g_assert (rv == CKR_OK);
+	object = gck_session_create_object_for_factory (session, factory, NULL, attrs, 2);
 	g_assert (object != NULL);
 	g_assert (GCK_IS_SECRET_SEARCH (object));
 
@@ -350,5 +346,6 @@ DEFINE_TEST(create_search_for_collection_no_match)
 	g_assert (vsize == 0);
 	g_free (vdata);
 
+	g_object_unref (object);
 	g_object_unref (ocoll);
 }
diff --git a/pkcs11/user-store/gck-user-private-key.c b/pkcs11/user-store/gck-user-private-key.c
index c6bff36..7577c72 100644
--- a/pkcs11/user-store/gck-user-private-key.c
+++ b/pkcs11/user-store/gck-user-private-key.c
@@ -61,29 +61,30 @@ G_DEFINE_TYPE_EXTENDED (GckUserPrivateKey, gck_user_private_key, GCK_TYPE_PRIVAT
  * INTERNAL 
  */
 
-static void
+static GckObject*
 factory_create_private_key (GckSession *session, GckTransaction *transaction, 
-                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
 	GckUserPrivateKey *key;
 	GckSexp *sexp;
-	
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (object);
+
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	sexp = gck_private_xsa_key_create_sexp (session, transaction, attrs, n_attrs);
 	if (sexp == NULL)
-		return;
-	
+		return NULL;
+
 	key = g_object_new (GCK_TYPE_USER_PRIVATE_KEY, "base-sexp", sexp,
 	                    "module", gck_session_get_module (session),
 	                    "manager", gck_manager_for_template (attrs, n_attrs, session),
 	                    NULL);
-	g_return_if_fail (!key->private_sexp);
+	g_return_val_if_fail (!key->private_sexp, NULL);
 	key->private_sexp = gck_sexp_ref (sexp);
-	
-	*object = GCK_OBJECT (key);
+
 	gck_sexp_unref (sexp);
+
+	gck_session_complete_object_creation (session, transaction, GCK_OBJECT (key), attrs, n_attrs);
+	return GCK_OBJECT (key);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/pkcs11/user-store/gck-user-public-key.c b/pkcs11/user-store/gck-user-public-key.c
index 6f7e255..6b2d69c 100644
--- a/pkcs11/user-store/gck-user-public-key.c
+++ b/pkcs11/user-store/gck-user-public-key.c
@@ -46,23 +46,26 @@ G_DEFINE_TYPE_EXTENDED (GckUserPublicKey, gck_user_public_key, GCK_TYPE_PUBLIC_X
  * INTERNAL
  */
 
-static void
+static GckObject*
 factory_create_public_key (GckSession *session, GckTransaction *transaction, 
-                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
+	GckObject *object = NULL;
 	GckSexp *sexp;
-	
-	g_return_if_fail (attrs || !n_attrs);
-	g_return_if_fail (object);
+
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
 	sexp = gck_public_xsa_key_create_sexp (session, transaction, attrs, n_attrs);
 	if (sexp != NULL) {
-		*object = g_object_new (GCK_TYPE_USER_PUBLIC_KEY, "base-sexp", sexp,
-		                        "module", gck_session_get_module (session),
-		                        "manager", gck_manager_for_template (attrs, n_attrs, session),
-		                        NULL);
+		object = g_object_new (GCK_TYPE_USER_PUBLIC_KEY, "base-sexp", sexp,
+		                       "module", gck_session_get_module (session),
+		                       "manager", gck_manager_for_template (attrs, n_attrs, session),
+		                       NULL);
 		gck_sexp_unref (sexp);
+		gck_session_complete_object_creation (session, transaction, object, attrs, n_attrs);
 	}
+
+	return object;
 }
 
 /* -----------------------------------------------------------------------------



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