[gcr] gck: Add GckBuilder as a mutable attribute set



commit cb64b5ec5ff1b7ae50bfa09267f05011f9b8de96
Author: Stef Walter <stefw collabora co uk>
Date:   Mon Dec 5 17:56:03 2011 +0100

    gck: Add GckBuilder as a mutable attribute set
    
     * Use GckBuilder to build a set of attributes, and then
       GckAttributes is a immutable set of attributes.
     * We reference count the memory used in attributes, so
       as we copy and transfer the attributes without duplicating
       values unnecessarily

 docs/reference/gck/gck.types           |    2 +-
 gck/gck-attributes.c                   | 2219 ++++++++++++++++++--------------
 gck/gck-dump.c                         |    8 +-
 gck/gck-enumerator.c                   |   24 +-
 gck/gck-mock.c                         |  251 ++--
 gck/gck-object.c                       |   95 +-
 gck/gck-private.h                      |   14 +-
 gck/gck-session.c                      |   29 -
 gck/gck-uri.c                          |   11 +-
 gck/gck.h                              |  195 ++-
 gck/gck.symbols                        |   57 +-
 gck/tests/test-gck-attributes.c        | 1034 ++++++++++++---
 gck/tests/test-gck-crypto.c            |   31 +-
 gck/tests/test-gck-enumerator.c        |   21 +-
 gck/tests/test-gck-modules.c           |    5 +-
 gck/tests/test-gck-object.c            |   56 +-
 gck/tests/test-gck-session.c           |    9 +-
 gck/tests/test-gck-uri.c               |   33 +-
 gcr/gcr-base.symbols                   |    1 +
 gcr/gcr-certificate-renderer.c         |    7 +-
 gcr/gcr-certificate-request-renderer.c |   16 +-
 gcr/gcr-gnupg-importer.c               |    5 +-
 gcr/gcr-gnupg-renderer.c               |    7 +-
 gcr/gcr-import-interaction.c           |   24 +-
 gcr/gcr-import-interaction.h           |   12 +-
 gcr/gcr-importer.c                     |    2 +-
 gcr/gcr-key-renderer.c                 |    9 +-
 gcr/gcr-openssh.c                      |  113 +-
 gcr/gcr-parser.c                       |   33 +-
 gcr/gcr-pkcs11-certificate.c           |   15 +-
 gcr/gcr-pkcs11-import-dialog.c         |   12 +-
 gcr/gcr-pkcs11-import-dialog.h         |    4 +-
 gcr/gcr-pkcs11-import-interaction.c    |   18 +-
 gcr/gcr-pkcs11-importer.c              |  109 +-
 gcr/gcr-subject-public-key.c           |  175 ++--
 gcr/gcr-trust.c                        |   69 +-
 gcr/gcr.symbols                        |    1 +
 gcr/tests/frob-parser.c                |    2 +-
 gcr/tests/test-certificate-chain.c     |   41 +-
 gcr/tests/test-fingerprint.c           |   13 +-
 gcr/tests/test-pkcs11-certificate.c    |   19 +-
 gcr/tests/test-subject-public-key.c    |   30 +-
 gcr/tests/test-trust.c                 |   15 +-
 43 files changed, 2929 insertions(+), 1917 deletions(-)
---
diff --git a/docs/reference/gck/gck.types b/docs/reference/gck/gck.types
index b5c5d32..773f02a 100644
--- a/docs/reference/gck/gck.types
+++ b/docs/reference/gck/gck.types
@@ -1,5 +1,5 @@
-gck_attribute_get_type
 gck_attributes_get_type
+gck_builder_get_type
 gck_module_info_get_type
 gck_module_get_type
 gck_enumerator_get_type
diff --git a/gck/gck-attributes.c b/gck/gck-attributes.c
index e3f244d..a48e44f 100644
--- a/gck/gck-attributes.c
+++ b/gck/gck-attributes.c
@@ -27,6 +27,8 @@
 #include "gck-private.h"
 #include "pkcs11-trust-assertions.h"
 
+#include "egg/egg-secure-memory.h"
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -35,8 +37,8 @@
  * @title: GckAttribute
  * @short_description: A PKCS11 attribute.
  *
- * This structure represents a PKCS11 CK_ATTRIBUTE. These attributes contain information
- * about a PKCS11 object. Use gck_object_get() or gck_object_set() to set and retrieve
+ * This structure represents a PKCS11 CK_ATTRIBUTE. These attributes contain i
+ * about a PKCS11 object. Use gck_object_get() or gck_object_set() to set and
  * attributes on an object.
  */
 
@@ -44,373 +46,877 @@
  * GckAttribute:
  * @type: The attribute type, such as CKA_LABEL.
  * @value: (array length=length): The value of the attribute. May be NULL.
- * @length: The length of the attribute. May be G_MAXULONG if the attribute is invalid.
+ * @length: The length of the attribute. May be G_MAXULONG if the attribute is
  *
  * This structure represents a PKCS11 CK_ATTRIBUTE.
  */
 
-/**
- * GCK_TYPE_ATTRIBUTES:
- *
- * Boxed type for #GckAttributes
- */
+G_STATIC_ASSERT (sizeof (GckAttribute) == sizeof (CK_ATTRIBUTE));
+
+struct _GckAttributes {
+	GckAttribute *data;
+	gulong count;
+	gint refs;
+};
+
+typedef struct {
+	GArray *array;
+	gboolean secure;
+	gint refs;
+} GckRealBuilder;
+
+G_STATIC_ASSERT (sizeof (GckRealBuilder) <= sizeof (GckBuilder));
+
+EGG_SECURE_DECLARE (attributes);
+
+static guchar *
+value_take (gpointer data,
+            gsize length,
+            gboolean secure)
+{
+	gsize len = length + sizeof (gint);
+	gint *value;
+
+	if (secure)
+		value = egg_secure_realloc (data, len);
+	else
+		value = g_realloc (data, len);
+	g_assert (value != NULL);
+
+	memmove (value + 1, value, length);
+	g_atomic_int_set (value, 1);
+	return (guchar *)(value + 1);
+}
+
+static guchar *
+value_blank (gsize length,
+             gboolean secure)
+{
+	gsize len = length + sizeof (gint);
+	gint *value;
+
+	if (secure)
+		value = egg_secure_alloc (len);
+	else
+		value = g_malloc (len);
+	g_assert (value != NULL);
+
+	g_atomic_int_set (value, 1);
+	return (guchar *)(value + 1);
+}
+
+static guchar *
+value_new (gconstpointer data,
+           gsize length,
+           gboolean secure)
+{
+	guchar *result;
+
+	result = value_blank (length, secure);
+	memcpy (result, data, length);
+	return result;
+}
+
+static guchar *
+value_ref (guchar *data)
+{
+	gint *value = ((gint *)data) - 1;
+	gint previous;
+
+	g_assert (data != NULL);
+
+#if GLIB_CHECK_VERSION (2,29,90)
+	previous = g_atomic_int_add (value, 1);
+#else
+	previous = g_atomic_int_exchange_and_add (value, 1);
+#endif
+
+	if (G_UNLIKELY (previous <= 0)) {
+		g_warning ("An owned GckAttribute value has been modified outside of the "
+		           "gck library or an invalid attribute was passed to gck_builder_add_attribute()");
+		return NULL;
+	}
+
+	return data;
+}
 
 static void
-attribute_init (GckAttribute *attr, gulong attr_type,
-                gconstpointer value, gsize length,
-                GckAllocator allocator)
+value_unref (gpointer data)
 {
-	g_assert (sizeof (GckAttribute) == sizeof (CK_ATTRIBUTE));
-	g_assert (allocator);
+	gint *value = ((gint *)data) - 1;
 
-	memset (attr, 0, sizeof (GckAttribute));
-	attr->type = attr_type;
-	attr->length = length;
-	if (value) {
-		attr->value = (allocator) (NULL, length ? length : 1);
-		g_assert (attr->value);
-		memcpy ((gpointer)attr->value, value, length);
+	g_assert (data != NULL);
+
+	if (g_atomic_int_dec_and_test (value)) {
+		if (egg_secure_check (value))
+			egg_secure_free (value);
+		else
+			g_free (value);
 	}
 }
 
-/**
- * gck_attribute_init: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: (array length=length): The raw value of the attribute.
- * @length: The length of the raw value.
- *
- * Initialize a PKCS\#11 attribute. This copies the value memory
- * into an internal buffer.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
+GType
+gck_builder_get_type (void)
+{
+	static volatile gsize initialized = 0;
+	static GType type = 0;
+	if (g_once_init_enter (&initialized)) {
+		type = g_boxed_type_register_static ("GckBuilder",
+		                                     (GBoxedCopyFunc)gck_builder_ref,
+		                                     (GBoxedFreeFunc)gck_builder_unref);
+		g_once_init_leave (&initialized, 1);
+	}
+	return type;
+}
+
+GckBuilder *
+gck_builder_new (GckBuilderFlags flags)
+{
+	GckBuilder *builder;
+	GckRealBuilder *real;
+	builder = g_slice_new (GckBuilder);
+	gck_builder_init_full (builder, flags);
+	real = (GckRealBuilder *)builder;
+	real->refs = 1;
+	return builder;
+}
+
+GckBuilder *
+gck_builder_ref (GckBuilder *builder)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	gboolean stack;
+
+	g_return_val_if_fail (builder != NULL, NULL);
+
+#if GLIB_CHECK_VERSION (2,29,90)
+	stack = g_atomic_int_add (&real->refs, 1) == 0;
+#else
+	stack = g_atomic_int_exchange_and_add (&real->refs, 1) == 0;
+#endif
+
+	if G_UNLIKELY (stack) {
+		g_warning ("Never call gck_builder_ref() on a stack allocated GckBuilder structure");
+		return NULL;
+	}
+
+	return builder;
+}
+
 void
-gck_attribute_init (GckAttribute *attr,
-                    gulong attr_type,
-                    const guchar *value,
-                    gsize length)
+gck_builder_unref (gpointer builder)
 {
-	g_return_if_fail (attr);
-	attribute_init (attr, attr_type, value, length, g_realloc);
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	if (builder == NULL)
+		return;
+
+	if (g_atomic_int_dec_and_test (&real->refs)) {
+		gck_builder_clear (builder);
+		g_slice_free (GckBuilder, builder);
+	}
 }
 
-/**
- * gck_attribute_init_invalid: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- *
- * Initialize a PKCS\#11 attribute to an 'invalid' or 'not found'
- * state. Specifically this sets the value length to (CK_ULONG)-1
- * as specified in the PKCS\#11 specification.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
 void
-gck_attribute_init_invalid (GckAttribute *attr, gulong attr_type)
+gck_builder_init_full (GckBuilder *builder,
+                       GckBuilderFlags flags)
 {
-	g_return_if_fail (attr);
-	g_assert (sizeof (GckAttribute) == sizeof (CK_ATTRIBUTE));
-	memset (attr, 0, sizeof (GckAttribute));
-	attr->type = attr_type;
-	attr->length = (gulong)-1;
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	g_return_if_fail (builder != NULL);
+
+	memset (builder, 0, sizeof (GckBuilder));
+	real->secure = flags & GCK_BUILDER_SECURE_MEMORY;
 }
 
-/**
- * gck_attribute_init_empty: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- *
- * Initialize a PKCS\#11 attribute to an empty state. The attribute
- * type will be set, but no data will be set.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
 void
-gck_attribute_init_empty (GckAttribute *attr, gulong attr_type)
+gck_builder_init (GckBuilder *builder)
+{
+	gck_builder_init_full (builder, GCK_BUILDER_NONE);
+}
+
+static GckAttribute *
+builder_push (GckBuilder *builder,
+              gulong attr_type)
+{
+	GckAttribute attr = { attr_type, NULL, 0 };
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	if (real->array == NULL)
+		real->array = g_array_new (FALSE, TRUE, sizeof (GckAttribute));
+	g_array_append_val (real->array, attr);
+	return &g_array_index (real->array, GckAttribute, real->array->len - 1);
+}
+
+static void
+builder_clear (GckAttribute *attr)
 {
-	g_return_if_fail (attr);
-	g_assert (sizeof (GckAttribute) == sizeof (CK_ATTRIBUTE));
-	memset (attr, 0, sizeof (GckAttribute));
-	attr->type = attr_type;
 	attr->length = 0;
-	attr->value = 0;
+	if (attr->value)
+		value_unref (attr->value);
+	attr->value = NULL;
+}
+
+static GckAttribute *
+find_attribute (GckAttribute *attrs,
+                gsize n_attrs,
+                gulong attr_type)
+{
+	guint i;
+
+	for (i = 0; i < n_attrs; ++i) {
+		if (attrs[i].type == attr_type)
+			return attrs + i;
+	}
+
+	return NULL;
+}
+
+static GckAttribute *
+builder_clear_or_push (GckBuilder *builder,
+                       gulong attr_type)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	GckAttribute *attr = NULL;
+
+	if (real->array)
+		attr = find_attribute ((GckAttribute *)real->array->data,
+		                       real->array->len, attr_type);
+	if (attr == NULL)
+		attr = builder_push (builder, attr_type);
+	else
+		builder_clear (attr);
+	return attr;
 }
 
 static void
-attribute_init_boolean (GckAttribute *attr, gulong attr_type,
-                        gboolean value, GckAllocator allocator)
+builder_copy (GckBuilder *builder,
+              const GckAttribute *attr,
+              gboolean performing_set)
 {
-	CK_BBOOL bvalue = value ? CK_TRUE : CK_FALSE;
-	attribute_init (attr, attr_type, &bvalue, sizeof (bvalue), allocator);
+	GckAttribute *copy;
+
+	if (performing_set)
+		copy = builder_clear_or_push (builder, attr->type);
+	else
+		copy = builder_push (builder, attr->type);
+	if (attr->length == G_MAXULONG) {
+		copy->value = NULL;
+		copy->length = G_MAXULONG;
+	} else if (attr->value == NULL) {
+		copy->value = NULL;
+		copy->length = 0;
+	} else {
+		copy->value = value_ref (attr->value);
+		copy->length = attr->length;
+	}
+}
+
+GckBuilder *
+gck_builder_copy (GckBuilder *builder)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	GckBuilder *copy;
+	guint i;
+
+	if (builder == NULL)
+		return NULL;
+
+	copy = gck_builder_new (real->secure ? GCK_BUILDER_SECURE_MEMORY : GCK_BUILDER_NONE);
+	for (i = 0; real->array && i < real->array->len; i++)
+		builder_copy (copy, &g_array_index (real->array, GckAttribute, i), FALSE);
+
+	return copy;
 }
 
-/**
- * gck_attribute_init_boolean: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The boolean value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to boolean. This will result
- * in a CK_BBOOL attribute from the PKCS\#11 specs.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
 void
-gck_attribute_init_boolean (GckAttribute *attr, gulong attr_type,
-                             gboolean value)
+gck_builder_take_data (GckBuilder *builder,
+                       gulong attr_type,
+                       guchar *value,
+                       gsize length)
 {
-	g_return_if_fail (attr);
-	attribute_init_boolean (attr, attr_type, value, g_realloc);
+	GckAttribute *attr;
+	gboolean secure;
+
+	g_return_if_fail (builder != NULL);
+
+	secure = value && egg_secure_check (value);
+
+	attr = builder_push (builder, attr_type);
+	if (length == G_MAXULONG) {
+		if (secure)
+			egg_secure_free (value);
+		else
+			g_free (value);
+		attr->value = NULL;
+		attr->length = G_MAXULONG;
+	} else if (value == NULL) {
+		attr->value = NULL;
+		attr->length = 0;
+	} else {
+		attr->value = value_take (value, length, secure);
+		attr->length = length;
+	}
+}
+
+void
+gck_builder_add_data (GckBuilder *builder,
+                      gulong attr_type,
+                      const guchar *value,
+                      gsize length)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	GckAttribute *attr;
+
+	g_return_if_fail (builder != NULL);
+
+	attr = builder_push (builder, attr_type);
+	if (length == G_MAXULONG) {
+		attr->value = NULL;
+		attr->length = G_MAXULONG;
+	} else if (value == NULL) {
+		attr->value = NULL;
+		attr->length = 0;
+	} else {
+		attr->value = value_new (value, length,
+		                         real->secure || egg_secure_check (value));
+		attr->length = length;
+	}
+}
+
+void
+gck_builder_set_data (GckBuilder *builder,
+                      gulong attr_type,
+                      const guchar *value,
+                      gsize length)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	GckAttribute *attr;
+
+	g_return_if_fail (builder != NULL);
+
+	attr = builder_clear_or_push (builder, attr_type);
+	if (length == G_MAXULONG) {
+		attr->value = NULL;
+		attr->length = G_MAXULONG;
+	} else if (value == NULL) {
+		attr->value = NULL;
+		attr->length = 0;
+	} else {
+		attr->value = value_new (value, length,
+		                         real->secure || egg_secure_check (value));
+		attr->length = length;
+	}
+}
+
+void
+gck_builder_add_empty (GckBuilder *builder,
+                       gulong attr_type)
+{
+	g_return_if_fail (builder != NULL);
+
+	builder_push (builder, attr_type);
+}
+
+void
+gck_builder_set_empty (GckBuilder *builder,
+                       gulong attr_type)
+{
+	g_return_if_fail (builder != NULL);
+
+	builder_clear_or_push (builder, attr_type);
+}
+
+void
+gck_builder_add_invalid (GckBuilder *builder,
+                         gulong attr_type)
+{
+	GckAttribute *attr;
+
+	g_return_if_fail (builder != NULL);
+
+	attr = builder_push (builder, attr_type);
+	attr->length = (gulong)-1;
+}
+
+void
+gck_builder_set_invalid (GckBuilder *builder,
+                         gulong attr_type)
+{
+	GckAttribute *attr;
+
+	g_return_if_fail (builder != NULL);
+
+	attr = builder_clear_or_push (builder, attr_type);
+	attr->length = (gulong)-1;
+}
+
+void
+gck_builder_add_ulong (GckBuilder *builder,
+                       gulong attr_type,
+                       gulong value)
+{
+	CK_ULONG uval = value;
+	gck_builder_add_data (builder, attr_type,
+	                      (const guchar *)&uval, sizeof (uval));
+}
+
+void
+gck_builder_set_ulong (GckBuilder *builder,
+                       gulong attr_type,
+                       gulong value)
+{
+	CK_ULONG uval = value;
+	gck_builder_set_data (builder, attr_type,
+	                      (const guchar *)&uval, sizeof (uval));
+}
+
+void
+gck_builder_add_boolean (GckBuilder *builder,
+                         gulong attr_type,
+                         gboolean value)
+{
+	CK_BBOOL bval = value ? CK_TRUE : CK_FALSE;
+	gck_builder_add_data (builder, attr_type,
+	                      (const guchar *)&bval, sizeof (bval));
+}
+
+void
+gck_builder_set_boolean (GckBuilder *builder,
+                         gulong attr_type,
+                         gboolean value)
+{
+	CK_BBOOL bval = value ? CK_TRUE : CK_FALSE;
+	gck_builder_set_data (builder, attr_type,
+	                      (const guchar *)&bval, sizeof (bval));
 }
 
 static void
-attribute_init_date (GckAttribute *attr, gulong attr_type,
-                     const GDate *value, GckAllocator allocator)
+convert_gdate_to_ckdate (const GDate *value,
+                         CK_DATE *date)
 {
 	gchar buffer[9];
-	CK_DATE date;
-	g_assert (value);
 	g_snprintf (buffer, sizeof (buffer), "%04d%02d%02d",
 	            (int)g_date_get_year (value),
 	            (int)g_date_get_month (value),
 	            (int)g_date_get_day (value));
-	memcpy (&date.year, buffer + 0, 4);
-	memcpy (&date.month, buffer + 4, 2);
-	memcpy (&date.day, buffer + 6, 2);
-	attribute_init (attr, attr_type, &date, sizeof (CK_DATE), allocator);
+	memcpy (&date->year, buffer + 0, 4);
+	memcpy (&date->month, buffer + 4, 2);
+	memcpy (&date->day, buffer + 6, 2);
 }
 
-/**
- * gck_attribute_init_date: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The date value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to a date. This will result
- * in a CK_DATE attribute from the PKCS\#11 specs.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
 void
-gck_attribute_init_date (GckAttribute *attr, gulong attr_type,
-                          const GDate *value)
+gck_builder_add_date (GckBuilder *builder,
+                      gulong attr_type,
+                      const GDate *value)
 {
-	g_return_if_fail (attr);
-	g_return_if_fail (value);
-	attribute_init_date (attr, attr_type, value, g_realloc);
+	CK_DATE date;
+
+	g_return_if_fail (value != NULL);
+
+	convert_gdate_to_ckdate (value, &date);
+	gck_builder_add_data (builder, attr_type,
+	                      (const guchar *)&date, sizeof (CK_DATE));
 }
 
-static void
-attribute_init_ulong (GckAttribute *attr, gulong attr_type,
-                      gulong value, GckAllocator allocator)
+void
+gck_builder_set_date (GckBuilder *builder,
+                      gulong attr_type,
+                      const GDate *value)
 {
-	CK_ULONG uvalue = value;
-	attribute_init (attr, attr_type, &uvalue, sizeof (uvalue), allocator);
+	CK_DATE date;
+
+	g_return_if_fail (value != NULL);
+
+	convert_gdate_to_ckdate (value, &date);
+	gck_builder_set_data (builder, attr_type,
+	                      (const guchar *)&date, sizeof (CK_DATE));
 }
 
-/**
- * gck_attribute_init_ulong: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The ulong value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to a unsigned long. This will result
- * in a CK_ULONG attribute from the PKCS\#11 specs.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
 void
-gck_attribute_init_ulong (GckAttribute *attr, gulong attr_type,
-                           gulong value)
+gck_builder_add_string (GckBuilder *builder,
+                        gulong attr_type,
+                        const gchar *value)
 {
-	g_return_if_fail (attr);
-	attribute_init_ulong (attr, attr_type, value, g_realloc);
+	gck_builder_add_data (builder, attr_type,
+	                      (const guchar *)value, value ? strlen (value) : 0);
 }
 
-static void
-attribute_init_string (GckAttribute *attr, gulong attr_type,
-                       const gchar *value, GckAllocator allocator)
+void
+gck_builder_set_string (GckBuilder *builder,
+                        gulong attr_type,
+                        const gchar *value)
 {
-	gsize len = value ? strlen (value) : 0;
-	attribute_init (attr, attr_type, (gpointer)value, len, allocator);
+	gck_builder_set_data (builder, attr_type,
+	                      (const guchar *)value, value ? strlen (value) : 0);
 }
 
-/**
- * gck_attribute_init_string: (skip)
- * @attr: An uninitialized attribute.
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The null terminated string value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to a string. This will result
- * in an attribute containing the text, but not the null terminator.
- * The text in the attribute will be of the same encoding as you pass
- * to this function.
- *
- * When done with the attribute you should use gck_attribute_clear()
- * to free the internal memory.
- **/
 void
-gck_attribute_init_string (GckAttribute *attr, gulong attr_type,
-                            const gchar *value)
+gck_builder_add_attribute (GckBuilder *builder,
+                           const GckAttribute *attr)
 {
-	g_return_if_fail (attr);
-	attribute_init_string (attr, attr_type, value, g_realloc);
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attr != NULL);
+
+	gck_builder_add_data (builder, attr->type, attr->value, attr->length);
+}
+
+void
+gck_builder_add_owned (GckBuilder *builder,
+                       const GckAttribute *attr)
+{
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attr != NULL);
+
+	builder_copy (builder, attr, FALSE);
+}
+
+void
+gck_builder_add_all (GckBuilder *builder,
+                     GckAttributes *attrs)
+{
+	gulong i;
+
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attrs != NULL);
+
+	for (i = 0; i < attrs->count; i++)
+		builder_copy (builder, &attrs->data[i], FALSE);
+}
+
+void
+gck_builder_add_only (GckBuilder *builder,
+                      GckAttributes *attrs,
+                      gulong only_type,
+                      ...)
+{
+	GArray *types;
+	va_list va;
+
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attrs != NULL);
+
+	types = g_array_new (FALSE, FALSE, sizeof (gulong));
+
+	va_start (va, only_type);
+	while (only_type != GCK_INVALID) {
+		g_array_append_val (types, only_type);
+		only_type = va_arg (va, gulong);
+	}
+	va_end (va);
+
+	gck_builder_add_onlyv (builder, attrs, (gulong *)types->data, types->len);
+	g_array_free (types, TRUE);
+}
+
+void
+gck_builder_add_onlyv (GckBuilder *builder,
+                       GckAttributes *attrs,
+                       const gulong *only_types,
+                       guint n_only_types)
+{
+	gulong i;
+	guint j;
+
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attrs != NULL);
+
+	for (i = 0; i < attrs->count; i++) {
+		for (j = 0; j < n_only_types; j++) {
+			if (attrs->data[i].type == only_types[j])
+				builder_copy (builder, &attrs->data[i], FALSE);
+		}
+	}
+}
+
+void
+gck_builder_add_except (GckBuilder *builder,
+                        GckAttributes *attrs,
+                        gulong except_type,
+                        ...)
+{
+	GArray *types;
+	va_list va;
+
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attrs != NULL);
+
+	types = g_array_new (FALSE, FALSE, sizeof (gulong));
+
+	va_start (va, except_type);
+	while (except_type != GCK_INVALID) {
+		g_array_append_val (types, except_type);
+		except_type = va_arg (va, gulong);
+	}
+	va_end (va);
+
+	gck_builder_add_exceptv (builder, attrs, (gulong *)types->data, types->len);
+	g_array_free (types, TRUE);
+}
+
+void
+gck_builder_add_exceptv (GckBuilder *builder,
+                         GckAttributes *attrs,
+                         const gulong *except_types,
+                         guint n_except_types)
+{
+	gulong i;
+	guint j;
+
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attrs != NULL);
+
+	for (i = 0; i < attrs->count; i++) {
+		for (j = 0; j < n_except_types; j++) {
+			if (attrs->data[i].type == except_types[j])
+				break;
+		}
+		if (j == n_except_types)
+			builder_copy (builder, &attrs->data[i], FALSE);
+	}
+}
+
+void
+gck_builder_set_all (GckBuilder *builder,
+                     GckAttributes *attrs)
+{
+	gulong i;
+
+	g_return_if_fail (builder != NULL);
+	g_return_if_fail (attrs != NULL);
+
+	for (i = 0; i < attrs->count; i++)
+		builder_copy (builder, &attrs->data[i], TRUE);
+}
+
+const GckAttribute *
+gck_builder_find (GckBuilder *builder,
+                  gulong attr_type)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	g_return_val_if_fail (builder != NULL, NULL);
+
+	if (real->array == NULL)
+		return NULL;
+
+	return find_attribute ((GckAttribute *)real->array->data,
+	                       real->array->len, attr_type);
+}
+
+static gboolean
+find_attribute_boolean (GckAttribute *attrs,
+                        gsize n_attrs,
+                        gulong attr_type,
+                        gboolean *value)
+{
+	GckAttribute *attr;
+
+	attr = find_attribute (attrs, n_attrs, attr_type);
+	if (!attr || gck_attribute_is_invalid (attr))
+		return FALSE;
+	*value = gck_attribute_get_boolean (attr);
+	return TRUE;
+}
+
+
+gboolean
+gck_builder_find_boolean (GckBuilder *builder,
+                          gulong attr_type,
+                          gboolean *value)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	g_return_val_if_fail (builder != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	if (real->array == NULL)
+		return FALSE;
+
+	return find_attribute_boolean ((GckAttribute *)real->array->data,
+	                               real->array->len, attr_type, value);
+}
+
+static gboolean
+find_attribute_ulong (GckAttribute *attrs,
+                      gsize n_attrs,
+                      gulong attr_type,
+                      gulong *value)
+{
+	GckAttribute *attr;
+
+	attr = find_attribute (attrs, n_attrs, attr_type);
+	if (!attr || gck_attribute_is_invalid (attr))
+		return FALSE;
+	*value = gck_attribute_get_ulong (attr);
+	return TRUE;
+}
+
+gboolean
+gck_builder_find_ulong (GckBuilder *builder,
+                        gulong attr_type,
+                        gulong *value)
+{
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	g_return_val_if_fail (builder != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	if (real->array == NULL)
+		return FALSE;
+
+	return find_attribute_ulong ((GckAttribute *)real->array->data,
+	                             real->array->len, attr_type, value);
+}
+
+static gboolean
+find_attribute_string (GckAttribute *attrs,
+                       gsize n_attrs,
+                       gulong attr_type,
+                       gchar **value)
+{
+	GckAttribute *attr;
+	gchar *string;
+
+	attr = find_attribute (attrs, n_attrs, attr_type);
+	if (!attr || gck_attribute_is_invalid (attr))
+		return FALSE;
+	string = gck_attribute_get_string (attr);
+	if (string == NULL)
+		return FALSE;
+	*value = string;
+	return TRUE;
 }
 
-GType
-gck_attribute_get_type (void)
+gboolean
+gck_builder_find_string (GckBuilder *builder,
+                         gulong attr_type,
+                         gchar **value)
 {
-	static volatile gsize initialized = 0;
-	static GType type = 0;
-	if (g_once_init_enter (&initialized)) {
-		type = g_boxed_type_register_static ("GckAttribute",
-		                                     (GBoxedCopyFunc)gck_attribute_dup,
-		                                     (GBoxedFreeFunc)gck_attribute_free);
-		g_once_init_leave (&initialized, 1);
-	}
-	return type;
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	g_return_val_if_fail (builder != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	if (real->array == NULL)
+		return FALSE;
+
+	return find_attribute_string ((GckAttribute *)real->array->data,
+	                              real->array->len, attr_type, value);
 }
 
-/**
- * gck_attribute_new:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The raw value of the attribute.
- * @length: The length of the attribute.
- *
- * Create a new PKCS\#11 attribute. The value will be copied
- * into the new attribute.
- *
- * Returns: (transfer full): the new attribute; when done with the attribute
- *          use gck_attribute_free() to free it
- **/
-GckAttribute*
-gck_attribute_new (gulong attr_type, gpointer value, gsize length)
+static gboolean
+find_attribute_date (GckAttribute *attrs,
+                     gsize n_attrs,
+                     gulong attr_type,
+                     GDate *value)
 {
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	attribute_init (attr, attr_type, value, length, g_realloc);
-	return attr;
-}
+	GckAttribute *attr;
 
-/**
- * gck_attribute_new_invalid:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- *
- * Create a new PKCS\#11 attribute as 'invalid' or 'not found'
- * state. Specifically this sets the value length to (CK_ULONG)-1
- * as specified in the PKCS\#11 specification.
- *
- * Returns: (transfer full): the new attribute; when done with the attribute
- *          use gck_attribute_free() to free it
- **/
-GckAttribute*
-gck_attribute_new_invalid (gulong attr_type)
+	attr = find_attribute (attrs, n_attrs, attr_type);
+	if (!attr || gck_attribute_is_invalid (attr))
+		return FALSE;
+	gck_attribute_get_date (attr, value);
+	return TRUE;
+}
+gboolean
+gck_builder_find_date (GckBuilder *builder,
+                       gulong attr_type,
+                       GDate *value)
 {
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	gck_attribute_init_invalid (attr, attr_type);
-	return attr;
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+
+	g_return_val_if_fail (builder != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	if (real->array == NULL)
+		return FALSE;
+
+	return find_attribute_date ((GckAttribute *)real->array->data,
+	                            real->array->len, attr_type, value);
 }
 
-/**
- * gck_attribute_new_empty:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- *
- * Create a new PKCS\#11 attribute with empty data.
- *
- * Returns: (transfer full): the new attribute; when done with the attribute
- *          use gck_attribute_free() to free it
- */
-GckAttribute*
-gck_attribute_new_empty (gulong attr_type)
+GckAttributes *
+gck_builder_steal (GckBuilder *builder)
 {
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	gck_attribute_init_empty (attr, attr_type);
-	return attr;
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	GckAttributes *attrs;
+	gpointer data;
+	gulong length;
+
+	g_return_val_if_fail (builder != NULL, NULL);
+
+	if (real->array) {
+		length = real->array->len;
+		data = g_array_free (real->array, FALSE);
+		real->array = NULL;
+	} else {
+		length = 0;
+		data = NULL;
+	}
+
+	attrs = g_slice_new0 (GckAttributes);
+	attrs->count = length;
+	attrs->data = data;
+	attrs->refs = 1;
+
+	return attrs;
 }
 
-/**
- * gck_attribute_new_boolean:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The boolean value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to boolean. This will result
- * in a CK_BBOOL attribute from the PKCS\#11 specs.
- *
- * Returns: (transfer full): the new attribute; when done with the attribute use
- *          gck_attribute_free() to free it
- **/
-GckAttribute*
-gck_attribute_new_boolean (gulong attr_type, gboolean value)
+GckAttributes *
+gck_builder_end (GckBuilder *builder)
 {
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	attribute_init_boolean (attr, attr_type, value, g_realloc);
-	return attr;
+	GckAttributes *attrs;
+
+	g_return_val_if_fail (builder != NULL, NULL);
+
+	attrs = gck_builder_steal (builder);
+	gck_builder_clear (builder);
+
+	return attrs;
 }
 
-/**
- * gck_attribute_new_date:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The date value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to a date. This will result
- * in a CK_DATE attribute from the PKCS\#11 specs.
- *
- * Returns: (transfer full): the new attribute; when done with the attribute use
- *          gck_attribute_free() to free it
- **/
-GckAttribute*
-gck_attribute_new_date (gulong attr_type, const GDate *value)
+void
+gck_builder_clear (GckBuilder *builder)
 {
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	attribute_init_date (attr, attr_type, value, g_realloc);
-	return attr;
+	GckRealBuilder *real = (GckRealBuilder *)builder;
+	GckAttribute *attr;
+	guint i;
+
+	g_return_if_fail (builder != NULL);
+
+	if (real->array == NULL)
+		return;
+
+	for (i = 0; i < real->array->len; i++) {
+		attr = &g_array_index (real->array, GckAttribute, i);
+		builder_clear (attr);
+	}
+
+	g_array_free (real->array, TRUE);
+	real->array = NULL;
 }
 
 /**
- * gck_attribute_new_ulong:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The ulong value of the attribute.
+ * SECTION:gck-attribute
+ * @title: GckAttribute
+ * @short_description: A PKCS11 attribute.
  *
- * Initialize a PKCS\#11 attribute to a unsigned long. This will result
- * in a CK_ULONG attribute from the PKCS\#11 specs.
+ * This structure represents a PKCS11 CK_ATTRIBUTE. These attributes contain information
+ * about a PKCS11 object. Use gck_object_get() or gck_object_set() to set and retrieve
+ * attributes on an object.
  *
- * Returns: (transfer full): the new attribute; when done with the attribute use
- *          gck_attribute_free() to free it
- **/
-GckAttribute*
-gck_attribute_new_ulong (gulong attr_type, gulong value)
-{
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	attribute_init_ulong (attr, attr_type, value, g_realloc);
-	return attr;
-}
+ * Although you are free to allocate a #GckAttribute in your own code, no functions in
+ * this library will operate on such an attribute.
+ */
 
 /**
- * gck_attribute_new_string:
- * @attr_type: The PKCS\#11 attribute type to set on the attribute.
- * @value: The null terminated string value of the attribute.
- *
- * Initialize a PKCS\#11 attribute to a string. This will result
- * in an attribute containing the text, but not the null terminator.
- * The text in the attribute will be of the same encoding as you pass
- * to this function.
+ * GckAttribute:
+ * @type: The attribute type, such as CKA_LABEL.
+ * @value: (array length=length): The value of the attribute. May be NULL.
+ * @length: The length of the attribute. May be G_MAXULONG if the attribute is invalid.
  *
- * Returns: (transfer full): the new attribute; when done with the attribute use
- *          gck_attribute_free() to free it
- **/
-GckAttribute*
-gck_attribute_new_string (gulong attr_type, const gchar *value)
-{
-	GckAttribute *attr = g_slice_new0 (GckAttribute);
-	attribute_init_string (attr, attr_type, value, g_realloc);
-	return attr;
-}
+ * This structure represents a PKCS11 CK_ATTRIBUTE.
+ */
 
 /**
  * gck_attribute_is_invalid:
@@ -423,7 +929,7 @@ gck_attribute_new_string (gulong attr_type, const gchar *value)
  * Return value: Whether the attribute represents invalid or not.
  */
 gboolean
-gck_attribute_is_invalid (GckAttribute *attr)
+gck_attribute_is_invalid (const GckAttribute *attr)
 {
 	g_return_val_if_fail (attr, TRUE);
 	return attr->length == (gulong)-1;
@@ -441,7 +947,7 @@ gck_attribute_is_invalid (GckAttribute *attr)
  * Return value: The boolean value of the attribute.
  */
 gboolean
-gck_attribute_get_boolean (GckAttribute *attr)
+gck_attribute_get_boolean (const GckAttribute *attr)
 {
 	gboolean value;
 
@@ -465,7 +971,7 @@ gck_attribute_get_boolean (GckAttribute *attr)
  * Return value: The ulong value of the attribute.
  */
 gulong
-gck_attribute_get_ulong (GckAttribute *attr)
+gck_attribute_get_ulong (const GckAttribute *attr)
 {
 	gulong value;
 
@@ -490,7 +996,7 @@ gck_attribute_get_ulong (GckAttribute *attr)
  *               g_free(), or %NULL if the value was invalid
  */
 gchar*
-gck_attribute_get_string (GckAttribute *attr)
+gck_attribute_get_string (const GckAttribute *attr)
 {
 	g_return_val_if_fail (attr, NULL);
 
@@ -513,7 +1019,8 @@ gck_attribute_get_string (GckAttribute *attr)
  * a value of the right type.
  */
 void
-gck_attribute_get_date (GckAttribute *attr, GDate *value)
+gck_attribute_get_date (const GckAttribute *attr,
+                        GDate *value)
 {
 	guint year, month, day;
 	gchar buffer[5];
@@ -550,695 +1057,567 @@ gck_attribute_get_date (GckAttribute *attr, GDate *value)
 }
 
 /**
- * gck_attribute_dup:
- * @attr: The attribute to duplicate.
+ * gck_attribute_init: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: (array length=length): The raw value of the attribute.
+ * @length: The length of the raw value.
  *
- * Duplicate the PKCS\#11 attribute. All value memory is
- * also copied.
+ * Initialize a PKCS\#11 attribute. This copies the value memory
+ * into an internal buffer.
  *
- * Returns: (transfer full): the duplicated attribute; use gck_attribute_free()
- *          to free it
- */
-GckAttribute*
-gck_attribute_dup (GckAttribute *attr)
-{
-	GckAttribute *copy;
-
-	if (!attr)
-		return NULL;
-
-	copy = g_slice_new0 (GckAttribute);
-	gck_attribute_init_copy (copy, attr);
-	return copy;
-}
-
-static void
-attribute_init_copy (GckAttribute *dest, const GckAttribute *src, GckAllocator allocator)
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
+ **/
+void
+gck_attribute_init (GckAttribute *attr,
+                    gulong attr_type,
+                    const guchar *value,
+                    gsize length)
 {
-	g_assert (dest);
-	g_assert (src);
-	g_assert (allocator);
-
-	/*
-	 * TODO: Handle stupid, dumb, broken, special cases like
-	 * CKA_WRAP_TEMPLATE and CKA_UNWRAP_TEMPLATE.
-	 */
+	g_return_if_fail (attr != NULL);
 
-	memcpy (dest, src, sizeof (GckAttribute));
-	if (src->value) {
-		dest->value = (allocator) (NULL, src->length ? src->length : 1);
-		g_assert (dest->value);
-		memcpy ((gpointer)dest->value, src->value, src->length);
+	attr->type = attr_type;
+	if (length == G_MAXULONG) {
+		attr->value = NULL;
+		attr->length = G_MAXULONG;
+	} else if (value == NULL) {
+		attr->value = NULL;
+		attr->length = 0;
+	} else {
+		attr->value = value_new (value, length, egg_secure_check (value));
+		attr->length = length;
 	}
 }
 
 /**
- * gck_attribute_init_copy:
- * @dest: An uninitialized attribute.
- * @src: An attribute to copy.
+ * gck_attribute_init_invalid: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
  *
- * Initialize a PKCS\#11 attribute as a copy of another attribute.
- * This copies the value memory as well.
+ * Initialize a PKCS\#11 attribute to an 'invalid' or 'not found'
+ * state. Specifically this sets the value length to (CK_ULONG)-1
+ * as specified in the PKCS\#11 specification.
  *
- * When done with the copied attribute you should use
- * gck_attribute_clear() to free the internal memory.
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
  **/
 void
-gck_attribute_init_copy (GckAttribute *dest, const GckAttribute *src)
-{
-	g_return_if_fail (dest);
-	g_return_if_fail (src);
-	attribute_init_copy (dest, src, g_realloc);
-}
-
-static void
-attribute_clear (GckAttribute *attr, GckAllocator allocator)
+gck_attribute_init_invalid (GckAttribute *attr,
+                            gulong attr_type)
 {
-	g_assert (attr);
-	g_assert (allocator);
-	if (attr->value)
-		(allocator) ((gpointer)attr->value, 0);
+	g_return_if_fail (attr != NULL);
+	attr->type = attr_type;
 	attr->value = NULL;
-	attr->length = 0;
+	attr->length = G_MAXULONG;
 }
 
 /**
- * gck_attribute_clear:
- * @attr: Attribute to clear.
- *
- * Clear allocated memory held by a statically allocated attribute.
- * These are usually initialized with gck_attribute_init() or a
- * similar function.
+ * gck_attribute_init_empty: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
  *
- * The type of the attribute will remain set.
- **/
-void
-gck_attribute_clear (GckAttribute *attr)
-{
-	g_return_if_fail (attr);
-	attribute_clear (attr, g_realloc);
-}
-
-/**
- * gck_attribute_free:
- * @attr: (type Gck.Attribute): attribute to free
+ * Initialize a PKCS\#11 attribute to an empty state. The attribute
+ * type will be set, but no data will be set.
  *
- * Free an attribute and its allocated memory. These is usually
- * used with attributes that are allocated by gck_attribute_new()
- * or a similar function.
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
  **/
 void
-gck_attribute_free (gpointer attr)
-{
-	GckAttribute *a = attr;
-	if (attr) {
-		attribute_clear (a, g_realloc);
-		g_slice_free (GckAttribute, a);
-	}
-}
-
-/**
- * gck_attribute_equal:
- * @attr1: (type Gck.Attribute): first attribute to compare
- * @attr2: (type Gck.Attribute): second attribute to compare
- *
- * Compare two attributes. Useful with <code>GHashTable</code>.
- *
- * Returns: %TRUE if the attributes are equal.
- */
-gboolean
-gck_attribute_equal (gconstpointer attr1,
-                     gconstpointer attr2)
+gck_attribute_init_empty (GckAttribute *attr, gulong attr_type)
 {
-	const GckAttribute *aa = attr1;
-	const GckAttribute *ab = attr2;
-
-	if (!aa && !ab)
-		return TRUE;
-	if (!aa || !ab)
-		return FALSE;
+	g_return_if_fail (attr != NULL);
 
-	if (aa->type != ab->type)
-		return FALSE;
-	if (aa->length != ab->length)
-		return FALSE;
-	if (!aa->value && !ab->value)
-		return TRUE;
-	if (!aa->value || !ab->value)
-		return FALSE;
-	return memcmp (aa->value, ab->value, aa->length) == 0;
+	attr->type = attr_type;
+	attr->length = 0;
+	attr->value = 0;
 }
 
 /**
- * gck_attribute_hash:
- * @attr: (type Gck.Attribute): attribute to hash
+ * gck_attribute_init_boolean: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the boolean value of the attribute
  *
- * Hash an attribute for use in <code>GHashTable</code> keys.
+ * Initialize a PKCS\#11 attribute to boolean. This will result
+ * in a CK_BBOOL attribute from the PKCS\#11 specs.
  *
- * Returns: the hash code
- */
-guint
-gck_attribute_hash (gconstpointer attr)
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
+ **/
+void
+gck_attribute_init_boolean (GckAttribute *attr,
+                            gulong attr_type,
+                            gboolean value)
 {
-	const GckAttribute *a = attr;
-	const signed char *p, *e;
-	guint32 h = 5381;
+	CK_BBOOL val = value ? CK_TRUE : CK_FALSE;
+	g_return_if_fail (attr != NULL);
+	gck_attribute_init (attr, attr_type, &val, sizeof (val));
+}
 
-	h ^= _gck_ulong_hash (&a->type);
+/**
+ * gck_attribute_init_date: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the date value of the attribute
+ *
+ * Initialize a PKCS\#11 attribute to a date. This will result
+ * in a CK_DATE attribute from the PKCS\#11 specs.
+ *
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
+ **/
+void
+gck_attribute_init_date (GckAttribute *attr,
+                         gulong attr_type,
+                         const GDate *value)
+{
+	CK_DATE date;
 
-	for (p = (signed char *)a->value, e = p + a->length; p != e; p++)
-		h = (h << 5) + h + *p;
+	g_return_if_fail (attr != NULL);
+	g_return_if_fail (value != NULL);
 
-	return h;
+	convert_gdate_to_ckdate (value, &date);
+	gck_attribute_init (attr, attr_type, (const guchar *)&date, sizeof (CK_DATE));
 }
 
 /**
- * SECTION:gck-attributes
- * @title: GckAttributes
- * @short_description: A set of PKCS11 attributes.
+ * gck_attribute_init_ulong: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the ulong value of the attribute
  *
- * A set of GckAttribute structures. These attributes contain information
- * about a PKCS11 object. Use gck_object_get() or gck_object_set() to set and retrieve
- * attributes on an object.
- */
-
-/**
- * GckAttributes:
+ * Initialize a PKCS\#11 attribute to a unsigned long. This will result
+ * in a CK_ULONG attribute from the PKCS\#11 specs.
  *
- * A set of GckAttribute structures.
- */
-struct _GckAttributes {
-	GArray *array;
-	GckAllocator allocator;
-	gboolean locked;
-	gint refs;
-};
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
+ **/
+void
+gck_attribute_init_ulong (GckAttribute *attr,
+                          gulong attr_type,
+                          gulong value)
+{
+	CK_ULONG val = value;
+	g_return_if_fail (attr != NULL);
+	gck_attribute_init (attr, attr_type, (const guchar *)&val, sizeof (val));
+}
 
 /**
- * GckAllocator:
- * @data: Memory to allocate or deallocate.
- * @length: New length of memory.
- *
- * An allocator used to allocate data for the attributes in this GckAttributes set.
+ * gck_attribute_init_string: (skip)
+ * @attr: an uninitialized attribute
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the null terminated string value of the attribute
  *
- * This is a function that acts like g_realloc. Specifically it frees when length is
- * set to zero, it allocates when data is set to NULL, and it reallocates when both
- * are valid.
+ * Initialize a PKCS\#11 attribute to a string. This will result
+ * in an attribute containing the text, but not the null terminator.
+ * The text in the attribute will be of the same encoding as you pass
+ * to this function.
  *
- * Returns: The allocated memory, or NULL when freeing.
+ * When done with the attribute you should use gck_attribute_clear()
+ * to free the internal memory.
  **/
+void
+gck_attribute_init_string (GckAttribute *attr,
+                           gulong attr_type,
+                           const gchar *value)
+{
+	g_return_if_fail (attr != NULL);
+	gck_attribute_init (attr, attr_type, (const guchar *)value,
+	                    value ? strlen (value) : 0);
+}
 
 GType
-gck_attributes_get_type (void)
+gck_attribute_get_type (void)
 {
 	static volatile gsize initialized = 0;
 	static GType type = 0;
 	if (g_once_init_enter (&initialized)) {
-		type = g_boxed_type_register_static ("GckAttributes",
-		                                     (GBoxedCopyFunc)gck_attributes_ref,
-		                                     (GBoxedFreeFunc)gck_attributes_unref);
+		type = g_boxed_type_register_static ("GckAttribute",
+		                                     (GBoxedCopyFunc)gck_attribute_dup,
+		                                     (GBoxedFreeFunc)gck_attribute_free);
 		g_once_init_leave (&initialized, 1);
 	}
 	return type;
 }
 
-GType
-gck_attributes_get_boxed_type (void)
-{
-	/* Deprecated version */
-	return gck_attributes_get_type ();
-}
-
 /**
- * gck_attributes_new:
+ * gck_attribute_new:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the raw value of the attribute
+ * @length: the length of the attribute
  *
- * Create a new GckAttributes array.
+ * Create a new PKCS\#11 attribute. The value will be copied
+ * into the new attribute.
  *
- * Returns: (transfer full): the new attributes array; when done with the array
- *          release it with gck_attributes_unref().
+ * Returns: (transfer full): the new attribute; when done with the attribute
+ *          use gck_attribute_free() to free it
  **/
-GckAttributes*
-gck_attributes_new (void)
+GckAttribute *
+gck_attribute_new (gulong attr_type,
+                   const guchar *value,
+                   gsize length)
 {
-	return gck_attributes_new_full (g_realloc);
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init (attr, attr_type, value, length);
+	return attr;
 }
 
 /**
- * gck_attributes_new_full: (skip)
- * @allocator: Memory allocator for attribute data, or NULL for default.
+ * gck_attribute_new_invalid:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
  *
- * Create a new GckAttributes array.
+ * Create a new PKCS\#11 attribute as 'invalid' or 'not found'
+ * state. Specifically this sets the value length to (CK_ULONG)-1
+ * as specified in the PKCS\#11 specification.
  *
- * Returns: (transfer full): the new attributes array; when done with the array
- *          release it with gck_attributes_unref()
+ * Returns: (transfer full): the new attribute; when done with the attribute
+ *          use gck_attribute_free() to free it
  **/
-GckAttributes*
-gck_attributes_new_full (GckAllocator allocator)
+GckAttribute *
+gck_attribute_new_invalid (gulong attr_type)
 {
-	GckAttributes *attrs;
-
-	if (!allocator)
-		allocator = g_realloc;
-
-	g_assert (sizeof (GckAttribute) == sizeof (CK_ATTRIBUTE));
-	attrs = g_slice_new0 (GckAttributes);
-	attrs->array = g_array_new (0, 1, sizeof (GckAttribute));
-	attrs->allocator = allocator;
-	attrs->refs = 1;
-	attrs->locked = FALSE;
-	return attrs;
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init_invalid (attr, attr_type);
+	return attr;
 }
 
 /**
- * gck_attributes_new_empty: (skip)
- * @attr_type: The first attribute type to add as empty.
- * @...: The arguments should be values of attribute types, terminated with gck_INVALID.
+ * gck_attribute_new_empty:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
  *
- * Creates an GckAttributes array with empty attributes. The arguments
- * should be values of attribute types, terminated with gck_INVALID.
+ * Create a new PKCS\#11 attribute with empty data.
  *
- * Returns: (transfer full): the new attributes array; when done with the array
- *          release it with gck_attributes_unref()
- **/
-GckAttributes*
-gck_attributes_new_empty (gulong attr_type, ...)
+ * Returns: (transfer full): the new attribute; when done with the attribute
+ *          use gck_attribute_free() to free it
+ */
+GckAttribute *
+gck_attribute_new_empty (gulong attr_type)
 {
-	GckAttributes *attrs = gck_attributes_new_full (g_realloc);
-	va_list va;
-
-	va_start (va, attr_type);
-
-	while (attr_type != GCK_INVALID) {
-		gck_attributes_add_empty (attrs, attr_type);
-		attr_type = va_arg (va, gulong);
-	}
-
-	va_end (va);
-
-	return attrs;
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init_empty (attr, attr_type);
+	return attr;
 }
 
 /**
- * gck_attributes_at:
- * @attrs: The attributes array.
- * @index: The attribute index to retrieve.
- *
- * Get attribute at the specified index in the attribute array.
+ * gck_attribute_new_boolean:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the boolean value of the attribute
  *
- * Use gck_attributes_count() to determine how many attributes are
- * in the array.
+ * Initialize a PKCS\#11 attribute to boolean. This will result
+ * in a CK_BBOOL attribute from the PKCS\#11 specs.
  *
- * Returns: (transfer none): the specified attribute
+ * Returns: (transfer full): the new attribute; when done with the attribute u
+ *          gck_attribute_free() to free it
  **/
-GckAttribute*
-gck_attributes_at (GckAttributes *attrs, guint index)
-{
-	g_return_val_if_fail (attrs && attrs->array, NULL);
-	g_return_val_if_fail (index < attrs->array->len, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	return &g_array_index (attrs->array, GckAttribute, index);
-}
-
-static GckAttribute*
-attributes_push (GckAttributes *attrs)
+GckAttribute *
+gck_attribute_new_boolean (gulong attr_type,
+                           gboolean value)
 {
-	GckAttribute attr;
-	g_assert (!attrs->locked);
-	memset (&attr, 0, sizeof (attr));
-	g_array_append_val (attrs->array, attr);
-	return &g_array_index (attrs->array, GckAttribute, attrs->array->len - 1);
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init_boolean (attr, attr_type, value);
+	return attr;
 }
 
 /**
- * gck_attributes_add:
- * @attrs: The attributes array to add to
- * @attr: The attribute to add.
- *
- * Add the specified attribute to the array.
+ * gck_attribute_new_date:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the date value of the attribute
  *
- * The value stored in the attribute will be copied.
+ * Initialize a PKCS\#11 attribute to a date. This will result
+ * in a CK_DATE attribute from the PKCS\#11 specs.
  *
- * Returns: (transfer none): the attribute that was added
+ * Returns: (transfer full): the new attribute; when done with the attribute u
+ *          gck_attribute_free() to free it
  **/
 GckAttribute *
-gck_attributes_add (GckAttributes *attrs, GckAttribute *attr)
+gck_attribute_new_date (gulong attr_type,
+                        const GDate *value)
 {
-	GckAttribute *added;
-	g_return_val_if_fail (attrs && attrs->array, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	g_return_val_if_fail (attr, NULL);
-	added = attributes_push (attrs);
-	attribute_init_copy (added, attr, attrs->allocator);
-	return added;
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init_date (attr, attr_type, value);
+	return attr;
 }
 
 /**
- * gck_attributes_set:
- * @attrs: attributes array to add to
- * @attr: attribute to set
- *
- * Set an attribute on the array.
+ * gck_attribute_new_ulong:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the ulong value of the attribute
  *
- * The value stored in the attribute will be copied.
+ * Initialize a PKCS\#11 attribute to a unsigned long. This will result
+ * in a CK_ULONG attribute from the PKCS\#11 specs.
  *
- * Returns: (transfer none): the attribute that was added
+ * Returns: (transfer full): the new attribute; when done with the attribute u
+ *          gck_attribute_free() to free it
  **/
-void
-gck_attributes_set (GckAttributes *attrs,
-                    GckAttribute *attr)
+GckAttribute *
+gck_attribute_new_ulong (gulong attr_type,
+                         gulong value)
 {
-	GckAttribute *orig;
-
-	g_return_if_fail (attrs != NULL);
-	g_return_if_fail (!attrs->locked);
-	g_return_if_fail (attr != NULL);
-
-	orig = gck_attributes_find (attrs, attr->type);
-	if (orig == NULL) {
-		gck_attributes_add (attrs, attr);
-	} else {
-		attribute_clear (orig, attrs->allocator);
-		attribute_init_copy (orig, attr, attrs->allocator);
-	}
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init_ulong (attr, attr_type, value);
+	return attr;
 }
 
 /**
- * gck_attributes_add_data:
- * @attrs: The attributes array to add to.
- * @attr_type: The type of attribute to add.
- * @value: (array length=length): the raw memory of the attribute value
- * @length: The length of the attribute value.
- *
- * Add an attribute with the specified type and value to the array.
+ * gck_attribute_new_string:
+ * @attr_type: the PKCS\#11 attribute type to set on the attribute
+ * @value: the null-terminated string value of the attribute
  *
- * The value stored in the attribute will be copied.
+ * Initialize a PKCS\#11 attribute to a string. This will result
+ * in an attribute containing the text, but not the null terminator.
+ * The text in the attribute will be of the same encoding as you pass
+ * to this function.
  *
- * Returns: (transfer none): the attribute that was added
+ * Returns: (transfer full): the new attribute; when done with the attribute u
+ *          gck_attribute_free() to free it
  **/
 GckAttribute *
-gck_attributes_add_data (GckAttributes *attrs,
-                         gulong attr_type,
-                         const guchar *value,
-                         gsize length)
+gck_attribute_new_string (gulong attr_type,
+                          const gchar *value)
 {
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	attribute_init (added, attr_type, value, length, attrs->allocator);
-	return added;
+	GckAttribute *attr = g_slice_new0 (GckAttribute);
+	gck_attribute_init_string (attr, attr_type, value);
+	return attr;
 }
 
 /**
- * gck_attributes_add_invalid:
- * @attrs: The attributes array to add to.
- * @attr_type: The type of attribute to add.
+ * gck_attribute_dup:
+ * @attr: the attribute to duplicate
+ *
+ * Duplicate the PKCS\#11 attribute. All value memory is
+ * also copied.
  *
- * Add an attribute with the specified type and an 'invalid' value to the array.
+ * The @attr must have been allocated or initialized by a Gck function or
+ * the results of this function are undefined.
  *
- * Returns: (transfer none): the attribute that was added
- **/
+ * Returns: (transfer full): the duplicated attribute; use gck_attribute_free()
+ *          to free it
+ */
 GckAttribute *
-gck_attributes_add_invalid (GckAttributes *attrs, gulong attr_type)
+gck_attribute_dup (const GckAttribute *attr)
 {
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	gck_attribute_init_invalid (added, attr_type);
-	return added;
+	GckAttribute *copy;
+
+	if (!attr)
+		return NULL;
+
+	copy = g_slice_new0 (GckAttribute);
+	gck_attribute_init_copy (copy, attr);
+	return copy;
 }
 
 /**
- * gck_attributes_add_empty:
- * @attrs: The attributes array to add.
- * @attr_type: The type of attribute to add.
+ * gck_attribute_init_copy:
+ * @dest: An uninitialized attribute.
+ * @src: An attribute to copy.
  *
- * Add an attribute with the specified type, with empty data.
+ * Initialize a PKCS\#11 attribute as a copy of another attribute.
+ * This copies the value memory as well.
  *
- * Returns: (transfer none): the attribute that was added
+ * When done with the copied attribute you should use
+ * gck_attribute_clear() to free the internal memory.
  **/
-GckAttribute *
-gck_attributes_add_empty (GckAttributes *attrs, gulong attr_type)
-{
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	gck_attribute_init_empty (added, attr_type);
-	return added;
+void
+gck_attribute_init_copy (GckAttribute *dest,
+                         const GckAttribute *src)
+{
+	g_return_if_fail (dest != NULL);
+	g_return_if_fail (src != NULL);
+
+	dest->type = src->type;
+	if (src->length == G_MAXULONG) {
+		dest->value = NULL;
+		dest->length = G_MAXULONG;
+	} else if (src->value == NULL) {
+		dest->value = NULL;
+		dest->length = 0;
+	} else {
+		dest->value = value_ref (src->value);
+		dest->length = src->length;
+	}
 }
 
 /**
- * gck_attributes_add_boolean:
- * @attrs: The attributes array to add to.
- * @attr_type: The type of attribute to add.
- * @value: The boolean value to add.
+ * gck_attribute_clear:
+ * @attr: Attribute to clear.
  *
- * Add an attribute with the specified type and value to the array.
+ * Clear allocated memory held by a #GckAttribute.
  *
- * The value will be stored as a CK_BBOOL PKCS\#11 style attribute.
+ * This attribute must have been allocated by a Gck library function, or
+ * the results of this method are undefined.
  *
- * Returns: (transfer none): the attribute that was added
+ * The type of the attribute will remain set.
  **/
-GckAttribute *
-gck_attributes_add_boolean (GckAttributes *attrs, gulong attr_type, gboolean value)
+void
+gck_attribute_clear (GckAttribute *attr)
 {
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	attribute_init_boolean (added, attr_type, value, attrs->allocator);
-	return added;
+	g_return_if_fail (attr != NULL);
+
+	if (attr->value != NULL)
+		value_unref (attr->value);
+	attr->value = NULL;
+	attr->length = 0;
 }
 
 /**
- * gck_attributes_set_boolean:
- * @attrs: the attributes
- * @attr_type: the type of attribute to set
- * @value: boolean value to set
+ * gck_attribute_free:
+ * @attr: (type Gck.Attribute): attribute to free
  *
- * Set the attribute of attr_type in the attribute array to the given value.
- * If no such value exists, then add one.
- */
+ * Free an attribute and its allocated memory. These is usually
+ * used with attributes that are allocated by gck_attribute_new()
+ * or a similar function.
+ **/
 void
-gck_attributes_set_boolean (GckAttributes *attrs,
-                            gulong attr_type,
-                            gboolean value)
+gck_attribute_free (gpointer attr)
 {
-	GckAttribute *attr;
-
-	g_return_if_fail (attrs != NULL);
-	g_return_if_fail (!attrs->locked);
-
-	attr = gck_attributes_find (attrs, attr_type);
-	if (attr == NULL) {
-		gck_attributes_add_boolean (attrs, attr_type, value);
-	} else {
-		attribute_clear (attr, attrs->allocator);
-		attribute_init_boolean (attr, attr_type, value, attrs->allocator);
+	GckAttribute *a = attr;
+	if (attr) {
+		gck_attribute_clear (a);
+		g_slice_free (GckAttribute, a);
 	}
 }
 
 /**
- * gck_attributes_add_string:
- * @attrs: The attributes array to add to.
- * @attr_type: The type of attribute to add.
- * @value: The null terminated string value to add.
- *
- * Add an attribute with the specified type and value to the array.
+ * gck_attribute_equal:
+ * @attr1: (type Gck.Attribute): first attribute to compare
+ * @attr2: (type Gck.Attribute): second attribute to compare
  *
- * The value will be copied into the attribute.
+ * Compare two attributes. Useful with <code>GHashTable</code>.
  *
- * Returns: (transfer none): the attribute that was added
- **/
-GckAttribute *
-gck_attributes_add_string (GckAttributes *attrs, gulong attr_type, const gchar *value)
+ * Returns: %TRUE if the attributes are equal.
+ */
+gboolean
+gck_attribute_equal (gconstpointer attr1,
+                     gconstpointer attr2)
 {
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	attribute_init_string (added, attr_type, value, attrs->allocator);
-	return added;
+	const GckAttribute *aa = attr1;
+	const GckAttribute *ab = attr2;
+
+	if (!aa && !ab)
+		return TRUE;
+	if (!aa || !ab)
+		return FALSE;
+
+	if (aa->type != ab->type)
+		return FALSE;
+	if (aa->length != ab->length)
+		return FALSE;
+	if (!aa->value && !ab->value)
+		return TRUE;
+	if (!aa->value || !ab->value)
+		return FALSE;
+	return memcmp (aa->value, ab->value, aa->length) == 0;
 }
 
 /**
- * gck_attributes_set_string:
- * @attrs: the attributes
- * @attr_type: the type of attribute to set
- * @value: null terminated string value to set
+ * gck_attribute_hash:
+ * @attr: (type Gck.Attribute): attribute to hash
+ *
+ * Hash an attribute for use in <code>GHashTable</code> keys.
  *
- * Set the attribute of attr_type in the attribute array to the given value.
- * If no such value exists, then add one.
+ * Returns: the hash code
  */
-void
-gck_attributes_set_string (GckAttributes *attrs,
-                           gulong attr_type,
-                           const gchar *value)
+guint
+gck_attribute_hash (gconstpointer attr)
 {
-	GckAttribute *attr;
+	const GckAttribute *a = attr;
+	const signed char *p, *e;
+	guint32 h = 5381;
 
-	g_return_if_fail (attrs != NULL);
-	g_return_if_fail (!attrs->locked);
+	h ^= _gck_ulong_hash (&a->type);
 
-	attr = gck_attributes_find (attrs, attr_type);
-	if (attr == NULL) {
-		gck_attributes_add_string (attrs, attr_type, value);
-	} else {
-		attribute_clear (attr, attrs->allocator);
-		attribute_init_string (attr, attr_type, value, attrs->allocator);
-	}
+	for (p = (signed char *)a->value, e = p + a->length; p != e; p++)
+		h = (h << 5) + h + *p;
+
+	return h;
 }
 
 /**
- * gck_attributes_add_date:
- * @attrs: The attributes array to add to.
- * @attr_type: The type of attribute to add.
- * @value: The GDate value to add.
- *
- * Add an attribute with the specified type and value to the array.
- *
- * The value will be stored as a CK_DATE PKCS\#11 style attribute.
+ * SECTION:gck-attributes
+ * @title: GckAttributes
+ * @short_description: A set of PKCS11 attributes.
  *
- * Returns: (transfer none): the attribute that was added
- **/
-GckAttribute *
-gck_attributes_add_date (GckAttributes *attrs, gulong attr_type, const GDate *value)
-{
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	attribute_init_date (added, attr_type, value, attrs->allocator);
-	return added;
-}
+ * A set of GckAttribute structures. These attributes contain information
+ * about a PKCS11 object. Use gck_object_get() or gck_object_set() to set and retrieve
+ * attributes on an object.
+ */
 
 /**
- * gck_attributes_set_date:
- * @attrs: the attributes
- * @attr_type: the type of attribute to set
- * @value: date value to set
+ * GckAttributes:
  *
- * Set the attribute of attr_type in the attribute array to the given value.
- * If no such value exists, then add one.
+ * A set of GckAttribute structures.
  */
-void
-gck_attributes_set_date (GckAttributes *attrs,
-                         gulong attr_type,
-                         const GDate *value)
-{
-	GckAttribute *attr;
-
-	g_return_if_fail (attrs != NULL);
-	g_return_if_fail (!attrs->locked);
-
-	attr = gck_attributes_find (attrs, attr_type);
-	if (attr == NULL) {
-		gck_attributes_add_date (attrs, attr_type, value);
-	} else {
-		attribute_clear (attr, attrs->allocator);
-		attribute_init_date (attr, attr_type, value, attrs->allocator);
-	}
-}
 
 /**
- * gck_attributes_add_ulong:
- * @attrs: The attributes array to add to.
- * @attr_type: The type of attribute to add.
- * @value: The gulong value to add.
+ * GckAllocator:
+ * @data: Memory to allocate or deallocate.
+ * @length: New length of memory.
  *
- * Add an attribute with the specified type and value to the array.
+ * An allocator used to allocate data for the attributes in this GckAttributes set.
  *
- * The value will be stored as a CK_ULONG PKCS\#11 style attribute.
+ * This is a function that acts like g_realloc. Specifically it frees when length is
+ * set to zero, it allocates when data is set to NULL, and it reallocates when both
+ * are valid.
  *
- * Returns: (transfer none): the attribute that was added
+ * Returns: The allocated memory, or NULL when freeing.
  **/
-GckAttribute *
-gck_attributes_add_ulong (GckAttributes *attrs, gulong attr_type, gulong value)
+
+GType
+gck_attributes_get_type (void)
 {
-	GckAttribute *added;
-	g_return_val_if_fail (attrs, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
-	added = attributes_push (attrs);
-	attribute_init_ulong (added, attr_type, value, attrs->allocator);
-	return added;
+	static volatile gsize initialized = 0;
+	static GType type = 0;
+	if (g_once_init_enter (&initialized)) {
+		type = g_boxed_type_register_static ("GckAttributes",
+		                                     (GBoxedCopyFunc)gck_attributes_ref,
+		                                     (GBoxedFreeFunc)gck_attributes_unref);
+		g_once_init_leave (&initialized, 1);
+	}
+	return type;
 }
 
-/**
- * gck_attributes_set_ulong:
- * @attrs: the attributes
- * @attr_type: the type of attribute to set
- * @value: gulong value to set
- *
- * Set the attribute of attr_type in the attribute array to the given value.
- * If no such value exists, then add one.
- */
-void
-gck_attributes_set_ulong (GckAttributes *attrs,
-                          gulong attr_type,
-                          gulong value)
+GType
+gck_attributes_get_boxed_type (void)
 {
-	GckAttribute *attr;
-
-	g_return_if_fail (attrs != NULL);
-	g_return_if_fail (!attrs->locked);
-
-	attr = gck_attributes_find (attrs, attr_type);
-	if (attr == NULL) {
-		gck_attributes_add_ulong (attrs, attr_type, value);
-	} else {
-		attribute_clear (attr, attrs->allocator);
-		attribute_init_ulong (attr, attr_type, value, attrs->allocator);
-	}
+	/* Deprecated version */
+	return gck_attributes_get_type ();
 }
 
 /**
- * gck_attributes_add_all:
- * @attrs: A set of attributes
- * @from: Attributes to add
+ * gck_attributes_new_empty:
  *
- * Add all attributes in @from to @attrs.
- */
-void
-gck_attributes_add_all (GckAttributes *attrs, GckAttributes *from)
+ * Creates an GckAttributes array with no attributes.
+ *
+ * Returns: (transfer full): the new attributes array; when done with the array
+ *          release it with gck_attributes_unref()
+ **/
+GckAttributes *
+gck_attributes_new_empty (void)
 {
-	GckAttribute *attr;
-	guint i;
-
-	g_return_if_fail (attrs && attrs->array);
-	g_return_if_fail (from && from->array);
-	g_return_if_fail (!attrs->locked);
-
-	for (i = 0; i < from->array->len; ++i) {
-		attr = &g_array_index (from->array, GckAttribute, i);
-		gck_attributes_add (attrs, attr);
-	}
+	GckBuilder builder = GCK_BUILDER_INIT;
+	return gck_builder_end (&builder);
 }
 
-
 /**
- * gck_attributes_set_all:
- * @attrs: set of attributes
- * @from: attributes to add
+ * gck_attributes_at:
+ * @attrs: The attributes array.
+ * @index: The attribute index to retrieve.
  *
- * Set all attributes in @from on @attrs.
- */
-void
-gck_attributes_set_all (GckAttributes *attrs,
-                        GckAttributes *from)
+ * Get attribute at the specified index in the attribute array.
+ *
+ * Use gck_attributes_count() to determine how many attributes are
+ * in the array.
+ *
+ * Returns: (transfer none): the specified attribute
+ **/
+const GckAttribute *
+gck_attributes_at (GckAttributes *attrs,
+                   guint index)
 {
-	GckAttribute *attr;
-	guint i;
-
-	g_return_if_fail (attrs && attrs->array);
-	g_return_if_fail (from && from->array);
-	g_return_if_fail (!attrs->locked);
-
-	for (i = 0; i < from->array->len; ++i) {
-		attr = &g_array_index (from->array, GckAttribute, i);
-		gck_attributes_set (attrs, attr);
-	}
+	g_return_val_if_fail (attrs != NULL, NULL);
+	g_return_val_if_fail (index < attrs->count, NULL);
+	return attrs->data + index;
 }
 
 /**
@@ -1252,9 +1631,8 @@ gck_attributes_set_all (GckAttributes *attrs,
 gulong
 gck_attributes_count (GckAttributes *attrs)
 {
-	g_return_val_if_fail (attrs, 0);
-	g_return_val_if_fail (!attrs->locked, 0);
-	return attrs->array->len;
+	g_return_val_if_fail (attrs != NULL, 0);
+	return attrs->count;
 }
 
 /**
@@ -1267,22 +1645,13 @@ gck_attributes_count (GckAttributes *attrs)
  * Returns: (transfer none): the first attribute found with the specified type,
  *          or %NULL
  **/
-GckAttribute *
-gck_attributes_find (GckAttributes *attrs, gulong attr_type)
+const GckAttribute *
+gck_attributes_find (GckAttributes *attrs,
+                     gulong attr_type)
 {
-	GckAttribute *attr;
-	guint i;
-
-	g_return_val_if_fail (attrs && attrs->array, NULL);
-	g_return_val_if_fail (!attrs->locked, NULL);
+	g_return_val_if_fail (attrs != NULL, NULL);
 
-	for (i = 0; i < attrs->array->len; ++i) {
-		attr = gck_attributes_at (attrs, i);
-		if (attr->type == attr_type)
-			return attr;
-	}
-
-	return NULL;
+	return find_attribute (attrs->data, attrs->count, attr_type);
 }
 
 /**
@@ -1302,16 +1671,9 @@ gck_attributes_find (GckAttributes *attrs, gulong attr_type)
 gboolean
 gck_attributes_find_boolean (GckAttributes *attrs, gulong attr_type, gboolean *value)
 {
-	GckAttribute *attr;
-
 	g_return_val_if_fail (value, FALSE);
-	g_return_val_if_fail (!attrs->locked, FALSE);
 
-	attr = gck_attributes_find (attrs, attr_type);
-	if (!attr || gck_attribute_is_invalid (attr))
-		return FALSE;
-	*value = gck_attribute_get_boolean (attr);
-	return TRUE;
+	return find_attribute_boolean (attrs->data, attrs->count, attr_type, value);
 }
 
 /**
@@ -1331,16 +1693,9 @@ gck_attributes_find_boolean (GckAttributes *attrs, gulong attr_type, gboolean *v
 gboolean
 gck_attributes_find_ulong (GckAttributes *attrs, gulong attr_type, gulong *value)
 {
-	GckAttribute *attr;
-
 	g_return_val_if_fail (value, FALSE);
-	g_return_val_if_fail (!attrs->locked, FALSE);
 
-	attr = gck_attributes_find (attrs, attr_type);
-	if (!attr || gck_attribute_is_invalid (attr))
-		return FALSE;
-	*value = gck_attribute_get_ulong (attr);
-	return TRUE;
+	return find_attribute_ulong (attrs->data, attrs->count, attr_type, value);
 }
 
 /**
@@ -1360,20 +1715,9 @@ gck_attributes_find_ulong (GckAttributes *attrs, gulong attr_type, gulong *value
 gboolean
 gck_attributes_find_string (GckAttributes *attrs, gulong attr_type, gchar **value)
 {
-	GckAttribute *attr;
-	gchar *string;
-
 	g_return_val_if_fail (value, FALSE);
-	g_return_val_if_fail (!attrs->locked, FALSE);
 
-	attr = gck_attributes_find (attrs, attr_type);
-	if (!attr || gck_attribute_is_invalid (attr))
-		return FALSE;
-	string = gck_attribute_get_string (attr);
-	if (string == NULL)
-		return FALSE;
-	*value = string;
-	return TRUE;
+	return find_attribute_string (attrs->data, attrs->count, attr_type, value);
 }
 
 /**
@@ -1393,16 +1737,9 @@ gck_attributes_find_string (GckAttributes *attrs, gulong attr_type, gchar **valu
 gboolean
 gck_attributes_find_date (GckAttributes *attrs, gulong attr_type, GDate *value)
 {
-	GckAttribute *attr;
-
 	g_return_val_if_fail (value, FALSE);
-	g_return_val_if_fail (!attrs->locked, FALSE);
 
-	attr = gck_attributes_find (attrs, attr_type);
-	if (!attr || gck_attribute_is_invalid (attr))
-		return FALSE;
-	gck_attribute_get_date (attr, value);
-	return TRUE;
+	return find_attribute_date (attrs->data, attrs->count, attr_type, value);
 }
 
 /**
@@ -1433,45 +1770,24 @@ void
 gck_attributes_unref (gpointer attrs)
 {
 	GckAttributes *attrs_ = attrs;
+	const GckAttribute *attr;
 	guint i;
 
 	if (!attrs_)
 		return;
 
 	if (g_atomic_int_dec_and_test (&attrs_->refs)) {
-		g_return_if_fail (attrs_->array);
-		g_return_if_fail (!attrs_->locked);
-		for (i = 0; i < attrs_->array->len; ++i)
-			attribute_clear (gck_attributes_at (attrs_, i), attrs_->allocator);
-		g_array_free (attrs_->array, TRUE);
-		attrs_->array = NULL;
+		for (i = 0; i < attrs_->count; ++i) {
+			attr = gck_attributes_at (attrs_, i);
+			if (attr->value)
+				value_unref (attr->value);
+		}
+		g_free (attrs_->data);
 		g_slice_free (GckAttributes, attrs_);
 	}
 }
 
 /**
- * gck_attributes_dup:
- * @attrs: an attribute array
- *
- * Make a complete copy of the attributes and all values.
- *
- * Returns: (transfer full): the copy
- */
-GckAttributes *
-gck_attributes_dup (GckAttributes *attrs)
-{
-	GckAttributes *copy;
-
-	if (!attrs)
-		return NULL;
-
-	copy = gck_attributes_new_full (attrs->allocator);
-	gck_attributes_add_all (copy, attrs);
-
-	return copy;
-}
-
-/**
  * gck_attributes_contains:
  * @attrs: The attributes to check
  * @match: The attribute to find
@@ -1481,14 +1797,15 @@ gck_attributes_dup (GckAttributes *attrs)
  * Returns: %TRUE if the attributes contain the attribute.
  */
 gboolean
-gck_attributes_contains (GckAttributes *attrs, GckAttribute *match)
+gck_attributes_contains (GckAttributes *attrs,
+                         const GckAttribute *match)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	guint i;
 
-	g_return_val_if_fail (attrs && attrs->array, FALSE);
+	g_return_val_if_fail (attrs != NULL, FALSE);
 
-	for (i = 0; i < attrs->array->len; ++i) {
+	for (i = 0; i < attrs->count; ++i) {
 		attr = gck_attributes_at (attrs, i);
 		if (gck_attribute_equal (attr, match))
 			return TRUE;
@@ -1497,96 +1814,76 @@ gck_attributes_contains (GckAttributes *attrs, GckAttribute *match)
 	return FALSE;
 }
 
-
-
-/* -------------------------------------------------------------------------------------------
- * INTERNAL
- *
- * The idea is that while we're processing a GckAttributes array (via PKCS#11
- * C_GetAtributeValue for example) the calling application shouldn't access those
- * attributes at all, except to ref or unref them.
- *
- * We try to help debug this with our 'locked' states. The various processing
- * functions that accept GckAttributes lock the attributes while handing
- * them off to be processed (perhaps in a different thread). We check this locked
- * flag in all public functions accessing GckAttributes.
- *
- * The reason we don't use thread safe or atomic primitives here, is because:
- *  a) The attributes are 'locked' by the same thread that prepares the call.
- *  b) This is a debugging feature, and should not be relied on for correctness.
- */
-
-void
-_gck_attributes_lock (GckAttributes *attrs)
-{
-	g_assert (attrs);
-	g_assert (!attrs->locked);
-	attrs->locked = TRUE;
-}
-
-void
-_gck_attributes_unlock (GckAttributes *attrs)
-{
-	g_assert (attrs);
-	g_assert (attrs->locked);
-	attrs->locked = FALSE;
-}
-
 CK_ATTRIBUTE_PTR
-_gck_attributes_prepare_in (GckAttributes *attrs, CK_ULONG_PTR n_attrs)
+_gck_builder_prepare_in (GckBuilder *builder,
+                         CK_ULONG_PTR n_attrs)
 {
+	GckRealBuilder *real = (GckRealBuilder *)builder;
 	GckAttribute *attr;
 	guint i;
 
-	g_assert (attrs);
-	g_assert (n_attrs);
-	g_assert (attrs->locked);
+	g_return_val_if_fail (builder != NULL, NULL);
+	g_return_val_if_fail (n_attrs != NULL, NULL);
+
+	if (real->array == NULL) {
+		*n_attrs = 0;
+		return NULL;
+	}
 
 	/* Prepare the attributes to receive their length */
 
-	for (i = 0; i < attrs->array->len; ++i) {
-		attr = &g_array_index (attrs->array, GckAttribute, i);
-		attribute_clear (attr, attrs->allocator);
+	for (i = 0; i < real->array->len; ++i) {
+		attr = &g_array_index (real->array, GckAttribute, i);
+		if (attr->value != NULL) {
+			value_unref (attr->value);
+			attr->value = NULL;
+		}
+		attr->length = 0;
 	}
 
-	*n_attrs = attrs->array->len;
-	return (CK_ATTRIBUTE_PTR)attrs->array->data;
+	*n_attrs = real->array->len;
+	return (CK_ATTRIBUTE_PTR)real->array->data;
 }
 
 CK_ATTRIBUTE_PTR
-_gck_attributes_commit_in (GckAttributes *attrs, CK_ULONG_PTR n_attrs)
+_gck_builder_commit_in (GckBuilder *builder,
+                        CK_ULONG_PTR n_attrs)
 {
+	GckRealBuilder *real = (GckRealBuilder *)builder;
 	GckAttribute *attr;
 	guint i;
 
-	g_assert (attrs);
-	g_assert (n_attrs);
-	g_assert (attrs->locked);
+	g_return_val_if_fail (builder != NULL, NULL);
+	g_return_val_if_fail (n_attrs != NULL, NULL);
+
+	if (real->array == NULL) {
+		*n_attrs = 0;
+		return NULL;
+	}
 
 	/* Allocate each attribute with the length that was set */
 
-	for (i = 0; i < attrs->array->len; ++i) {
-		attr = &g_array_index (attrs->array, GckAttribute, i);
-		g_assert (!attr->value);
-		if (attr->length != 0 && attr->length != (gulong)-1) {
-			attr->value = (attrs->allocator) (NULL, attr->length);
-			g_assert (attr->value);
-		}
+	for (i = 0; i < real->array->len; ++i) {
+		attr = &g_array_index (real->array, GckAttribute, i);
+		if (attr->length != 0 && attr->length != (gulong)-1)
+			attr->value = value_blank (attr->length, real->secure);
+		else
+			attr->value = NULL;
 	}
 
-	*n_attrs = attrs->array->len;
-	return (CK_ATTRIBUTE_PTR)attrs->array->data;
+	*n_attrs = real->array->len;
+	return (CK_ATTRIBUTE_PTR)real->array->data;
 }
 
 CK_ATTRIBUTE_PTR
-_gck_attributes_commit_out (GckAttributes *attrs, CK_ULONG_PTR n_attrs)
+_gck_attributes_commit_out (GckAttributes *attrs,
+                            CK_ULONG_PTR n_attrs)
 {
-	g_assert (attrs);
-	g_assert (n_attrs);
-	g_assert (attrs->locked);
+	g_return_val_if_fail (attrs != NULL, NULL);
+	g_return_val_if_fail (n_attrs != NULL, NULL);
 
-	*n_attrs = attrs->array->len;
-	return (CK_ATTRIBUTE_PTR)attrs->array->data;
+	*n_attrs = attrs->count;
+	return (CK_ATTRIBUTE_PTR)attrs->data;
 }
 
 static gboolean
@@ -1945,10 +2242,10 @@ _gck_format_attributes (GString *output,
 	GckAttribute *attr;
 	guint count, i;
 
-	count = attrs->array->len;
+	count = attrs->count;
 	g_string_append_printf (output, "(%d) [", count);
 	for (i = 0; i < count; i++) {
-		attr = &g_array_index (attrs->array, GckAttribute, i);
+		attr = attrs->data + i;
 		if (i > 0)
 			g_string_append_c (output, ',');
 		g_string_append (output, " { ");
@@ -1977,7 +2274,7 @@ _gck_format_attributes (GString *output,
 
 /**
  * gck_attributes_to_string:
- * attrs: the attributes
+ * @attrs: the attributes
  *
  * Print out attributes to a string in aform that's useful for debugging
  * or logging.
diff --git a/gck/gck-dump.c b/gck/gck-dump.c
index e365b3a..4e9aeab 100644
--- a/gck/gck-dump.c
+++ b/gck/gck-dump.c
@@ -79,7 +79,7 @@ dump_assertion_type_value (gulong type)
 }
 
 static void
-dump_attribute_value (GckAttribute *attr)
+dump_attribute_value (const GckAttribute *attr)
 {
 	gchar *data;
 	gsize len;
@@ -204,7 +204,7 @@ dump_attribute_value (GckAttribute *attr)
 }
 
 static void
-dump_attribute_type (GckAttribute *attr)
+dump_attribute_type (const GckAttribute *attr)
 {
 	switch (attr->type) {
 	#define DX(x) case x: g_printerr ("%s", #x); break;
@@ -330,7 +330,7 @@ dump_attribute_type (GckAttribute *attr)
  * Dump the specified attribute using g_printerr().
  */
 void
-gck_attribute_dump (GckAttribute *attr)
+gck_attribute_dump (const GckAttribute *attr)
 {
 	dump_attribute_type (attr);
 	if (attr->length == G_MAXULONG) {
@@ -351,7 +351,7 @@ gck_attribute_dump (GckAttribute *attr)
 void
 gck_attributes_dump (GckAttributes *attrs)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	guint i, count;
 
 	for (i = 0, count = gck_attributes_count (attrs); i < count; ++i) {
diff --git a/gck/gck-enumerator.c b/gck/gck-enumerator.c
index 68dca60..f4573b5 100644
--- a/gck/gck-enumerator.c
+++ b/gck/gck-enumerator.c
@@ -205,8 +205,6 @@ cleanup_state (GckEnumeratorState *args)
 	args->object_type = 0;
 
 	if (args->match) {
-		if (args->match->attributes)
-			_gck_attributes_unlock (args->match->attributes);
 		gck_uri_data_free (args->match);
 		args->match = NULL;
 	}
@@ -480,6 +478,7 @@ state_results (GckEnumeratorState *args,
                gboolean forward)
 {
 	GckEnumeratorResult *result;
+	GckBuilder builder;
 	GckAttributes *attrs;
 	CK_ATTRIBUTE_PTR template;
 	CK_ULONG n_template;
@@ -517,25 +516,25 @@ state_results (GckEnumeratorState *args,
 			continue;
 		}
 
-		attrs = gck_attributes_new ();
+		gck_builder_init (&builder);
+
 		for (i = 0; i < args->object_iface->n_attribute_types; ++i)
-			gck_attributes_add_empty (attrs, args->object_iface->attribute_types[i]);
-		_gck_attributes_lock (attrs);
+			gck_builder_add_empty (&builder, args->object_iface->attribute_types[i]);
 
 		/* Ask for attribute sizes */
-		template = _gck_attributes_prepare_in (attrs, &n_template);
+		template = _gck_builder_prepare_in (&builder, &n_template);
 
 		rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
 		if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
 
 			/* Allocate memory for each value */
-			template = _gck_attributes_commit_in (attrs, &n_template);
+			template = _gck_builder_commit_in (&builder, &n_template);
 
 			/* Now get the actual values */
 			rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
 		}
 
-		_gck_attributes_unlock (attrs);
+		attrs = gck_builder_end (&builder);
 
 		if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
 			if (_gck_debugging) {
@@ -735,9 +734,6 @@ _gck_enumerator_new_for_modules (GList *modules,
 	state->handler = state_modules;
 	state->match = uri_data;
 
-	if (uri_data->attributes)
-		_gck_attributes_lock (uri_data->attributes);
-
 	created_enumerator (uri_data, "modules");
 	return self;
 }
@@ -760,9 +756,6 @@ _gck_enumerator_new_for_slots (GList *slots,
 	state->handler = state_slots;
 	state->match = uri_data;
 
-	if (uri_data->attributes)
-		_gck_attributes_lock (uri_data->attributes);
-
 	created_enumerator (uri_data, "slots");
 	return self;
 }
@@ -791,9 +784,6 @@ _gck_enumerator_new_for_session (GckSession *session,
 	state->funcs = gck_module_get_functions (module);
 	g_object_unref (module);
 
-	if (uri_data->attributes)
-		_gck_attributes_lock (uri_data->attributes);
-
 	created_enumerator (uri_data, "session");
 	return self;
 }
diff --git a/gck/gck-mock.c b/gck/gck-mock.c
index 716b149..4ee90d5 100644
--- a/gck/gck-mock.c
+++ b/gck/gck-mock.c
@@ -94,29 +94,49 @@ free_session (gpointer data)
 	g_free (sess);
 }
 
-static GckAttributes*
-lookup_object (Session *session, CK_OBJECT_HANDLE hObject)
+static GckAttributes *
+lookup_object (Session *session,
+               CK_OBJECT_HANDLE hObject,
+               GHashTable **table)
 {
 	GckAttributes *attrs;
+
 	attrs = g_hash_table_lookup (the_objects, GUINT_TO_POINTER (hObject));
-	if (!attrs)
-		attrs = g_hash_table_lookup (session->objects, GUINT_TO_POINTER (hObject));
-	return attrs;
+	if (attrs) {
+		if (table)
+			*table = the_objects;
+		return attrs;
+	}
+
+	attrs = g_hash_table_lookup (session->objects, GUINT_TO_POINTER (hObject));
+	if (attrs) {
+		if (table)
+			*table = session->objects;
+		return attrs;
+	}
+
+	return NULL;
 }
 
 CK_OBJECT_HANDLE
 gck_mock_module_take_object (GckAttributes *attrs)
 {
+	GckBuilder builder;
 	gboolean token;
 	guint handle;
 
 	g_return_val_if_fail (the_objects, 0);
 
 	handle = ++unique_identifier;
-	if (gck_attributes_find_boolean (attrs, CKA_TOKEN, &token))
+	if (gck_attributes_find_boolean (attrs, CKA_TOKEN, &token)) {
 		g_return_val_if_fail (token == TRUE, 0);
-	else
-		gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
+	} else {
+		gck_builder_init (&builder);
+		gck_builder_add_except (&builder, attrs, CKA_TOKEN, GCK_INVALID);
+		gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
+		gck_attributes_unref (attrs);
+		attrs = gck_builder_end (&builder);
+	}
 	g_hash_table_insert (the_objects, GUINT_TO_POINTER (handle), attrs);
 	return handle;
 }
@@ -164,7 +184,7 @@ enumerate_and_find_object (CK_OBJECT_HANDLE object, GckAttributes *attrs, gpoint
 {
 	FindObject *ctx = user_data;
 	CK_ATTRIBUTE_PTR match;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	CK_ULONG i;
 
 	for (i = 0; i < ctx->n_attrs; ++i) {
@@ -212,14 +232,37 @@ gck_mock_module_count_objects (CK_SESSION_HANDLE session)
 	return n_objects;
 }
 
+static GckAttributes *
+replace_attributes (GckAttributes *atts,
+                    CK_ATTRIBUTE_PTR attrs,
+                    CK_ULONG n_attrs)
+{
+	GckBuilder builder;
+	CK_ULONG i;
+	CK_ATTRIBUTE_PTR set;
+	gulong *types;
+
+	if (!n_attrs)
+		return gck_attributes_ref (atts);
+
+	gck_builder_init (&builder);
+	types = g_new0 (gulong, n_attrs);
+	for (i = 0; i < n_attrs; ++i) {
+		set = attrs + i;
+		types[i] = set->type;
+		gck_builder_add_data (&builder, set->type, set->pValue, set->ulValueLen);
+	}
+	gck_builder_add_exceptv (&builder, atts, types, n_attrs);
+	g_free (types);
+	return gck_builder_end (&builder);
+}
+
 void
 gck_mock_module_set_object (CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR attrs,
                             CK_ULONG n_attrs)
 {
-	CK_ULONG i;
 	GckAttributes *atts;
-	GckAttribute *attr;
-	CK_ATTRIBUTE_PTR set;
+	GckAttributes *replaced;
 
 	g_return_if_fail (object != 0);
 	g_return_if_fail (the_objects);
@@ -227,16 +270,11 @@ gck_mock_module_set_object (CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR attrs,
 	atts = g_hash_table_lookup (the_objects, GUINT_TO_POINTER (object));
 	g_return_if_fail (atts);
 
-	for (i = 0; i < n_attrs; ++i) {
-		set = attrs + i;
-		attr = gck_attributes_find (atts, set->type);
-		if (!attr) {
-			gck_attributes_add_data (atts, set->type, set->pValue, set->ulValueLen);
-		} else {
-			gck_attribute_clear (attr);
-			gck_attribute_init (attr, set->type, set->pValue, set->ulValueLen);
-		}
-	}
+	if (!n_attrs)
+		return;
+
+	replaced = replace_attributes (atts, attrs, n_attrs);
+	g_hash_table_replace (the_objects, GUINT_TO_POINTER (object), replaced);
 }
 
 void
@@ -250,7 +288,7 @@ gck_mock_module_set_pin (const gchar *password)
 CK_RV
 gck_mock_C_Initialize (CK_VOID_PTR pInitArgs)
 {
-	GckAttributes *attrs;
+	GckBuilder builder;
 	CK_ULONG value;
 	CK_C_INITIALIZE_ARGS_PTR args;
 
@@ -276,62 +314,58 @@ gck_mock_C_Initialize (CK_VOID_PTR pInitArgs)
 	the_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)gck_attributes_unref);
 
 	/* Our token object */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_string (attrs, CKA_LABEL, "TEST LABEL");
-	g_hash_table_insert (the_objects, GUINT_TO_POINTER (2), attrs);
+	gck_builder_init (&builder);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_string (&builder, CKA_LABEL, "TEST LABEL");
+	g_hash_table_insert (the_objects, GUINT_TO_POINTER (2), gck_builder_end (&builder));
 
 	/* Private capitalize key */
 	value = CKM_MOCK_CAPITALIZE;
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PRIVATE_KEY);
-	gck_attributes_add_string (attrs, CKA_LABEL, "Private Capitalize Key");
-	gck_attributes_add_data (attrs, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
-	gck_attributes_add_boolean (attrs, CKA_DECRYPT, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_PRIVATE, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_WRAP, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_UNWRAP, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_DERIVE, CK_TRUE);
-	gck_attributes_add_string (attrs, CKA_VALUE, "value");
-	gck_attributes_add_string (attrs, CKA_GNOME_UNIQUE, "unique1");
-	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PRIVATE_KEY_CAPITALIZE), attrs);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_string (&builder, CKA_LABEL, "Private Capitalize Key");
+	gck_builder_add_data (&builder, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
+	gck_builder_add_boolean (&builder, CKA_DECRYPT, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_PRIVATE, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_WRAP, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_UNWRAP, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_DERIVE, CK_TRUE);
+	gck_builder_add_string (&builder, CKA_VALUE, "value");
+	gck_builder_add_string (&builder, CKA_GNOME_UNIQUE, "unique1");
+	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PRIVATE_KEY_CAPITALIZE), gck_builder_end (&builder));
 
 	/* Public capitalize key */
 	value = CKM_MOCK_CAPITALIZE;
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
-	gck_attributes_add_string (attrs, CKA_LABEL, "Public Capitalize Key");
-	gck_attributes_add_data (attrs, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
-	gck_attributes_add_boolean (attrs, CKA_ENCRYPT, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_PRIVATE, CK_FALSE);
-	gck_attributes_add_string (attrs, CKA_VALUE, "value");
-	gck_attributes_add_string (attrs, CKA_GNOME_UNIQUE, "unique2");
-	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PUBLIC_KEY_CAPITALIZE), attrs);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_string (&builder, CKA_LABEL, "Public Capitalize Key");
+	gck_builder_add_data (&builder, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
+	gck_builder_add_boolean (&builder, CKA_ENCRYPT, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_PRIVATE, CK_FALSE);
+	gck_builder_add_string (&builder, CKA_VALUE, "value");
+	gck_builder_add_string (&builder, CKA_GNOME_UNIQUE, "unique2");
+	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PUBLIC_KEY_CAPITALIZE), gck_builder_end (&builder));
 
 	/* Private prefix key */
 	value = CKM_MOCK_PREFIX;
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PRIVATE_KEY);
-	gck_attributes_add_string (attrs, CKA_LABEL, "Private prefix key");
-	gck_attributes_add_data (attrs, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
-	gck_attributes_add_boolean (attrs, CKA_SIGN, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_PRIVATE, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_ALWAYS_AUTHENTICATE, CK_TRUE);
-	gck_attributes_add_string (attrs, CKA_VALUE, "value");
-	gck_attributes_add_string (attrs, CKA_GNOME_UNIQUE, "unique3");
-	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PRIVATE_KEY_PREFIX), attrs);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_string (&builder, CKA_LABEL, "Private prefix key");
+	gck_builder_add_data (&builder, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
+	gck_builder_add_boolean (&builder, CKA_SIGN, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_PRIVATE, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_ALWAYS_AUTHENTICATE, CK_TRUE);
+	gck_builder_add_string (&builder, CKA_VALUE, "value");
+	gck_builder_add_string (&builder, CKA_GNOME_UNIQUE, "unique3");
+	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PRIVATE_KEY_PREFIX), gck_builder_end (&builder));
 
 	/* Private prefix key */
 	value = CKM_MOCK_PREFIX;
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
-	gck_attributes_add_string (attrs, CKA_LABEL, "Public prefix key");
-	gck_attributes_add_data (attrs, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
-	gck_attributes_add_boolean (attrs, CKA_VERIFY, CK_TRUE);
-	gck_attributes_add_boolean (attrs, CKA_PRIVATE, CK_FALSE);
-	gck_attributes_add_string (attrs, CKA_VALUE, "value");
-	gck_attributes_add_string (attrs, CKA_GNOME_UNIQUE, "unique4");
-	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PUBLIC_KEY_PREFIX), attrs);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_string (&builder, CKA_LABEL, "Public prefix key");
+	gck_builder_add_data (&builder, CKA_ALLOWED_MECHANISMS, (const guchar *)&value, sizeof (value));
+	gck_builder_add_boolean (&builder, CKA_VERIFY, CK_TRUE);
+	gck_builder_add_boolean (&builder, CKA_PRIVATE, CK_FALSE);
+	gck_builder_add_string (&builder, CKA_VALUE, "value");
+	gck_builder_add_string (&builder, CKA_GNOME_UNIQUE, "unique4");
+	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PUBLIC_KEY_PREFIX), gck_builder_end (&builder));
 
 	logged_in = FALSE;
 	initialized = TRUE;
@@ -809,12 +843,13 @@ CK_RV
 gck_mock_C_CreateObject (CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
                          CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
 {
+	GckBuilder builder;
 	GckAttributes *attrs;
 	Session *session;
 	gboolean token, priv;
 	CK_OBJECT_CLASS klass;
 	CK_OBJECT_HANDLE object;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	CK_ULONG i;
 
 	g_return_val_if_fail (phObject, CKR_ARGUMENTS_BAD);
@@ -822,10 +857,11 @@ gck_mock_C_CreateObject (CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
 	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
 	g_return_val_if_fail (session, CKR_SESSION_HANDLE_INVALID);
 
-	attrs = gck_attributes_new ();
+	gck_builder_init (&builder);
 	for (i = 0; i < ulCount; ++i)
-		gck_attributes_add_data (attrs, pTemplate[i].type, pTemplate[i].pValue, pTemplate[i].ulValueLen);
+		gck_builder_add_data (&builder, pTemplate[i].type, pTemplate[i].pValue, pTemplate[i].ulValueLen);
 
+	attrs = gck_builder_end (&builder);
 	if (gck_attributes_find_boolean (attrs, CKA_PRIVATE, &priv) && priv) {
 		if (!logged_in) {
 			gck_attributes_unref (attrs);
@@ -880,7 +916,7 @@ gck_mock_C_DestroyObject (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
 	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
 	g_return_val_if_fail (session, CKR_SESSION_HANDLE_INVALID);
 
-	attrs = lookup_object (session, hObject);
+	attrs = lookup_object (session, hObject, NULL);
 	g_return_val_if_fail (attrs, CKR_OBJECT_HANDLE_INVALID);
 
 	if (gck_attributes_find_boolean (attrs, CKA_PRIVATE, &priv) && priv) {
@@ -908,7 +944,7 @@ gck_mock_C_GetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObje
 	CK_ATTRIBUTE_PTR result;
 	CK_RV ret = CKR_OK;
 	GckAttributes *attrs;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	Session *session;
 	CK_ULONG i;
 
@@ -916,7 +952,7 @@ gck_mock_C_GetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObje
 	if (session == NULL)
 		return CKR_SESSION_HANDLE_INVALID;
 
-	attrs = lookup_object (session, hObject);
+	attrs = lookup_object (session, hObject, NULL);
 	if (!attrs)
 		return CKR_OBJECT_HANDLE_INVALID;
 
@@ -959,26 +995,17 @@ gck_mock_C_SetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObje
 {
 	Session *session;
 	GckAttributes *attrs;
-	CK_ATTRIBUTE_PTR set;
-	GckAttribute *attr;
-	CK_ULONG i;
+	GckAttributes *replaced;
+	GHashTable *table;
 
 	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
 	g_return_val_if_fail (session, CKR_SESSION_HANDLE_INVALID);
 
-	attrs = lookup_object (session, hObject);
+	attrs = lookup_object (session, hObject, &table);
 	g_return_val_if_fail (attrs, CKR_OBJECT_HANDLE_INVALID);
 
-	for (i = 0; i < ulCount; ++i) {
-		set = pTemplate + i;
-		attr = gck_attributes_find (attrs, set->type);
-		if (!attr) {
-			gck_attributes_add_data (attrs, set->type, set->pValue, set->ulValueLen);
-		} else {
-			gck_attribute_clear (attr);
-			gck_attribute_init (attr, set->type, set->pValue, set->ulValueLen);
-		}
-	}
+	replaced = replace_attributes (attrs, pTemplate, ulCount);
+	g_hash_table_replace (table, GUINT_TO_POINTER (hObject), replaced);
 
 	return CKR_OK;
 }
@@ -994,7 +1021,7 @@ enumerate_and_find_objects (CK_OBJECT_HANDLE object, GckAttributes *attrs, gpoin
 {
 	FindObjects *ctx = user_data;
 	CK_ATTRIBUTE_PTR match;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	CK_ULONG i;
 
 	for (i = 0; i < ctx->count; ++i) {
@@ -1529,6 +1556,7 @@ gck_mock_unsupported_C_GenerateKeyPair (CK_SESSION_HANDLE hSession, CK_MECHANISM
                                         CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
                                         CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
 {
+	GckBuilder builder;
 	GckAttributes *attrs;
 	Session *session;
 	gboolean token;
@@ -1552,25 +1580,27 @@ gck_mock_unsupported_C_GenerateKeyPair (CK_SESSION_HANDLE hSession, CK_MECHANISM
 	    memcmp (pMechanism->pParameter, "generate", 9) != 0)
 		g_return_val_if_reached (CKR_MECHANISM_PARAM_INVALID);
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_string (attrs, CKA_VALUE, "generated");
+	gck_builder_init (&builder);
+	gck_builder_add_string (&builder, CKA_VALUE, "generated");
 	for (i = 0; i < ulPublicKeyAttributeCount; ++i)
-		gck_attributes_add_data (attrs, pPublicKeyTemplate[i].type,
+		gck_builder_add_data (&builder, pPublicKeyTemplate[i].type,
 		                         pPublicKeyTemplate[i].pValue,
 		                         pPublicKeyTemplate[i].ulValueLen);
 	*phPublicKey = ++unique_identifier;
+	attrs = gck_builder_end (&builder);
 	if (gck_attributes_find_boolean (attrs, CKA_TOKEN, &token) && token)
 		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phPublicKey), attrs);
 	else
 		g_hash_table_insert (session->objects, GUINT_TO_POINTER (*phPublicKey), attrs);
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_string (attrs, CKA_VALUE, "generated");
+	gck_builder_init (&builder);
+	gck_builder_add_string (&builder, CKA_VALUE, "generated");
 	for (i = 0; i < ulPrivateKeyAttributeCount; ++i)
-		gck_attributes_add_data (attrs, pPrivateKeyTemplate[i].type,
+		gck_builder_add_data (&builder, pPrivateKeyTemplate[i].type,
 		                         pPrivateKeyTemplate[i].pValue,
 		                         pPrivateKeyTemplate[i].ulValueLen);
 	*phPrivateKey = ++unique_identifier;
+	attrs = gck_builder_end (&builder);
 	if (gck_attributes_find_boolean (attrs, CKA_TOKEN, &token) && token)
 		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phPrivateKey), attrs);
 	else
@@ -1584,7 +1614,7 @@ gck_mock_unsupported_C_WrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMe
                                 CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
 {
 	GckAttributes *attrs;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	Session *session;
 
 	g_return_val_if_fail (pMechanism, CKR_MECHANISM_INVALID);
@@ -1595,10 +1625,10 @@ gck_mock_unsupported_C_WrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMe
 	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
 	g_return_val_if_fail (session != NULL, CKR_SESSION_HANDLE_INVALID);
 
-	attrs = lookup_object (session, hWrappingKey);
+	attrs = lookup_object (session, hWrappingKey, NULL);
 	g_return_val_if_fail (attrs, CKR_WRAPPING_KEY_HANDLE_INVALID);
 
-	attrs = lookup_object (session, hKey);
+	attrs = lookup_object (session, hKey, NULL);
 	g_return_val_if_fail (attrs, CKR_WRAPPED_KEY_INVALID);
 
 	if (pMechanism->mechanism != CKM_MOCK_WRAP)
@@ -1636,6 +1666,7 @@ gck_mock_unsupported_C_UnwrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR p
                                   CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
                                   CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
 {
+	GckBuilder builder;
 	GckAttributes *attrs;
 	Session *session;
 	gboolean token;
@@ -1652,7 +1683,7 @@ gck_mock_unsupported_C_UnwrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR p
 	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
 	g_return_val_if_fail (session != NULL, CKR_SESSION_HANDLE_INVALID);
 
-	attrs = lookup_object (session, hUnwrappingKey);
+	attrs = lookup_object (session, hUnwrappingKey, NULL);
 	g_return_val_if_fail (attrs, CKR_WRAPPING_KEY_HANDLE_INVALID);
 
 	if (pMechanism->mechanism != CKM_MOCK_WRAP)
@@ -1664,13 +1695,14 @@ gck_mock_unsupported_C_UnwrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR p
 			g_return_val_if_reached (CKR_MECHANISM_PARAM_INVALID);
 	}
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_VALUE, pWrappedKey, ulWrappedKeyLen);
+	gck_builder_init (&builder);
+	gck_builder_add_data (&builder, CKA_VALUE, pWrappedKey, ulWrappedKeyLen);
 	for (i = 0; i < ulCount; ++i)
-		gck_attributes_add_data (attrs, pTemplate[i].type,
+		gck_builder_add_data (&builder, pTemplate[i].type,
 		                         pTemplate[i].pValue,
 		                         pTemplate[i].ulValueLen);
 	*phKey = ++unique_identifier;
+	attrs = gck_builder_end (&builder);
 	if (gck_attributes_find_boolean (attrs, CKA_TOKEN, &token) && token)
 		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phKey), attrs);
 	else
@@ -1684,6 +1716,7 @@ gck_mock_unsupported_C_DeriveKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR p
                                   CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
                                   CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
 {
+	GckBuilder builder;
 	GckAttributes *attrs, *copy;
 	Session *session;
 	gboolean token;
@@ -1697,7 +1730,7 @@ gck_mock_unsupported_C_DeriveKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR p
 	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
 	g_return_val_if_fail (session, CKR_SESSION_HANDLE_INVALID);
 
-	attrs = lookup_object (session, hBaseKey);
+	attrs = lookup_object (session, hBaseKey, NULL);
 	g_return_val_if_fail (attrs, CKR_KEY_HANDLE_INVALID);
 
 	if (pMechanism->mechanism != CKM_MOCK_DERIVE)
@@ -1709,15 +1742,15 @@ gck_mock_unsupported_C_DeriveKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR p
 			g_return_val_if_reached (CKR_MECHANISM_PARAM_INVALID);
 	}
 
-	copy = gck_attributes_new ();
-	gck_attributes_add_string (copy, CKA_VALUE, "derived");
+	gck_builder_init (&builder);
+	gck_builder_add_string (&builder, CKA_VALUE, "derived");
 	for (i = 0; i < ulCount; ++i)
-		gck_attributes_add_data (copy, pTemplate[i].type,
-		                         pTemplate[i].pValue,
-		                         pTemplate[i].ulValueLen);
-	for (i = 0; i < gck_attributes_count (attrs); ++i)
-		gck_attributes_add (copy, gck_attributes_at (attrs, i));
+		gck_builder_add_data (&builder, pTemplate[i].type,
+		                      pTemplate[i].pValue,
+		                      pTemplate[i].ulValueLen);
+	gck_builder_add_all (&builder, attrs);
 	*phKey = ++unique_identifier;
+	copy = gck_builder_end (&builder);
 	if (gck_attributes_find_boolean (copy, CKA_TOKEN, &token) && token)
 		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phKey), copy);
 	else
diff --git a/gck/gck-object.c b/gck/gck-object.c
index 1cd041d..4b86984 100644
--- a/gck/gck-object.c
+++ b/gck/gck-object.c
@@ -520,15 +520,12 @@ gck_object_set (GckObject *self, GckAttributes *attrs,
 	g_return_val_if_fail (attrs != NULL, FALSE);
 	g_return_val_if_fail (!error || !*error, FALSE);
 
-	_gck_attributes_lock (attrs);
-
 	memset (&args, 0, sizeof (args));
 	args.attrs = attrs;
 	args.object = self->pv->handle;
 
 	ret = _gck_call_sync (self->pv->session, perform_set_attributes, NULL, &args, cancellable, error);
 
-	_gck_attributes_unlock (attrs);
 	return ret;
 }
 
@@ -555,7 +552,6 @@ gck_object_set_async (GckObject *self, GckAttributes *attrs, GCancellable *cance
 	args = _gck_call_async_prep (self->pv->session, self, perform_set_attributes,
 	                             NULL, sizeof (*args), free_set_attributes);
 
-	_gck_attributes_lock (attrs);
 	args->attrs = gck_attributes_ref (attrs);
 	args->object = self->pv->handle;
 
@@ -585,7 +581,6 @@ gck_object_set_finish (GckObject *self, GAsyncResult *result, GError **error)
 	/* Unlock the attributes we were using */
 	args = _gck_call_arguments (result, SetAttributes);
 	g_assert (args->attrs);
-	_gck_attributes_unlock (args->attrs);
 
 	return _gck_call_basic_finish (result, error);
 }
@@ -597,7 +592,7 @@ gck_object_set_finish (GckObject *self, GAsyncResult *result, GError **error)
 typedef struct _GetAttributes {
 	GckArguments base;
 	CK_OBJECT_HANDLE object;
-	GckAttributes *attrs;
+	GckBuilder builder;
 } GetAttributes;
 
 static CK_RV
@@ -607,11 +602,10 @@ perform_get_attributes (GetAttributes *args)
 	CK_ULONG n_attrs;
 	CK_RV rv;
 
-	g_assert (args);
-	g_assert (args->attrs);
+	g_assert (args != NULL);
 
 	/* Prepare all the attributes */
-	attrs = _gck_attributes_prepare_in (args->attrs, &n_attrs);
+	attrs = _gck_builder_prepare_in (&args->builder, &n_attrs);
 
 	/* Get the size of each value */
 	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
@@ -620,7 +614,7 @@ perform_get_attributes (GetAttributes *args)
 		return rv;
 
 	/* Allocate memory for each value */
-	attrs = _gck_attributes_commit_in (args->attrs, &n_attrs);
+	attrs = _gck_builder_commit_in (&args->builder, &n_attrs);
 
 	/* Now get the actual values */
 	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
@@ -635,9 +629,8 @@ perform_get_attributes (GetAttributes *args)
 static void
 free_get_attributes (GetAttributes *args)
 {
-	g_assert (args);
-	g_assert (args->attrs);
-	gck_attributes_unref (args->attrs);
+	g_assert (args != NULL);
+	gck_builder_clear (&args->builder);
 	g_free (args);
 }
 
@@ -708,32 +701,28 @@ gck_object_get_full (GckObject *self,
                      GError **error)
 {
 	GetAttributes args;
-	GckAttributes *attrs;
 	gboolean ret;
 	guint i;
 
 	g_return_val_if_fail (GCK_IS_OBJECT (self), NULL);
 	g_return_val_if_fail (!error || !*error, NULL);
 
-	attrs = gck_attributes_new ();
-	for (i = 0; i < n_attr_types; ++i)
-		gck_attributes_add_empty (attrs, attr_types[i]);
+	memset (&args, 0, sizeof (args));
 
-	_gck_attributes_lock (attrs);
+	gck_builder_init (&args.builder);
+	for (i = 0; i < n_attr_types; ++i)
+		gck_builder_add_empty (&args.builder, attr_types[i]);
 
-	memset (&args, 0, sizeof (args));
-	args.attrs = attrs;
 	args.object = self->pv->handle;
 
 	ret = _gck_call_sync (self->pv->session, perform_get_attributes, NULL, &args, cancellable, error);
-	_gck_attributes_unlock (attrs);
 
-	if (!ret) {
-		gck_attributes_unref (attrs);
-		attrs = NULL;
+	if (ret) {
+		return gck_builder_end (&args.builder);
+	} else {
+		gck_builder_clear (&args.builder);
+		return NULL;
 	}
-
-	return attrs;
 }
 
 /**
@@ -760,21 +749,18 @@ gck_object_get_async (GckObject *self,
                       GAsyncReadyCallback callback,
                       gpointer user_data)
 {
-	GckAttributes *attrs;
 	GetAttributes *args;
 	guint i;
 
 	g_return_if_fail (GCK_IS_OBJECT (self));
 
-	attrs = gck_attributes_new ();
-	for (i = 0; i < n_attr_types; ++i)
-		gck_attributes_add_empty (attrs, attr_types[i]);
-
 	args = _gck_call_async_prep (self->pv->session, self, perform_get_attributes,
 	                             NULL, sizeof (*args), free_get_attributes);
 
-	_gck_attributes_lock (attrs);
-	args->attrs = attrs;
+	gck_builder_init (&args->builder);
+	for (i = 0; i < n_attr_types; ++i)
+		gck_builder_add_empty (&args->builder, attr_types[i]);
+
 	args->object = self->pv->handle;
 
 	_gck_call_async_ready_go (args, cancellable, callback, user_data);
@@ -798,22 +784,17 @@ GckAttributes*
 gck_object_get_finish (GckObject *self, GAsyncResult *result, GError **error)
 {
 	GetAttributes *args;
-	GckAttributes *attrs;
 
 	g_return_val_if_fail (GCK_IS_OBJECT (self), NULL);
 	g_return_val_if_fail (GCK_IS_CALL (result), NULL);
 	g_return_val_if_fail (!error || !*error, NULL);
 
 	args = _gck_call_arguments (result, GetAttributes);
-	_gck_attributes_unlock (args->attrs);
-	attrs = gck_attributes_ref (args->attrs);
 
-	if (!_gck_call_basic_finish (result, error)) {
-		gck_attributes_unref (attrs);
-		attrs = NULL;
-	}
+	if (!_gck_call_basic_finish (result, error))
+		return NULL;
 
-	return attrs;
+	return gck_builder_end (&args->builder);
 }
 
 /* ---------------------------------------------------------------------------------
@@ -1087,8 +1068,6 @@ gck_object_set_template (GckObject *self, gulong attr_type, GckAttributes *attrs
 	g_return_val_if_fail (attrs, FALSE);
 	g_return_val_if_fail (!error || !*error, FALSE);
 
-	_gck_attributes_lock (attrs);
-
 	memset (&args, 0, sizeof (args));
 	args.attrs = attrs;
 	args.type = attr_type;
@@ -1096,7 +1075,6 @@ gck_object_set_template (GckObject *self, gulong attr_type, GckAttributes *attrs
 
 	ret = _gck_call_sync (self->pv->session, perform_set_template, NULL, &args, cancellable, error);
 
-	_gck_attributes_unlock (attrs);
 	return ret;
 }
 
@@ -1127,7 +1105,6 @@ gck_object_set_template_async (GckObject *self, gulong attr_type, GckAttributes
 	args = _gck_call_async_prep (self->pv->session, self, perform_set_template,
 	                             NULL, sizeof (*args), free_set_template);
 
-	_gck_attributes_lock (attrs);
 	args->attrs = gck_attributes_ref (attrs);
 	args->type = attr_type;
 	args->object = self->pv->handle;
@@ -1158,7 +1135,6 @@ gck_object_set_template_finish (GckObject *self, GAsyncResult *result, GError **
 	/* Unlock the attributes we were using */
 	args = _gck_call_arguments (result, set_template_args);
 	g_assert (args->attrs);
-	_gck_attributes_unlock (args->attrs);
 
 	return _gck_call_basic_finish (result, error);
 }
@@ -1171,7 +1147,7 @@ typedef struct _get_template_args {
 	GckArguments base;
 	CK_OBJECT_HANDLE object;
 	CK_ATTRIBUTE_TYPE type;
-	GckAttributes *attrs;
+	GckBuilder builder;
 } get_template_args;
 
 static CK_RV
@@ -1182,9 +1158,8 @@ perform_get_template (get_template_args *args)
 	CK_RV rv;
 
 	g_assert (args);
-	g_assert (!args->attrs);
 
-	args->attrs = gck_attributes_new ();
+	gck_builder_init (&args->builder);
 	attr.type = args->type;
 	attr.ulValueLen = 0;
 	attr.pValue = 0;
@@ -1197,11 +1172,10 @@ perform_get_template (get_template_args *args)
 	/* Number of attributes, rounded down */
 	n_attrs = (attr.ulValueLen / sizeof (CK_ATTRIBUTE));
 	for (i = 0; i < n_attrs; ++i)
-		gck_attributes_add_empty (args->attrs, 0);
+		gck_builder_add_empty (&args->builder, 0);
 
 	/* Prepare all the attributes */
-	_gck_attributes_lock (args->attrs);
-	attr.pValue = _gck_attributes_prepare_in (args->attrs, &n_attrs);
+	attr.pValue = _gck_builder_prepare_in (&args->builder, &n_attrs);
 
 	/* Get the size of each value */
 	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1);
@@ -1209,7 +1183,7 @@ perform_get_template (get_template_args *args)
 		return rv;
 
 	/* Allocate memory for each value */
-	attr.pValue = _gck_attributes_commit_in (args->attrs, &n_attrs);
+	attr.pValue = _gck_builder_commit_in (&args->builder, &n_attrs);
 
 	/* Now get the actual values */
 	return (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object, &attr, 1);
@@ -1218,8 +1192,8 @@ perform_get_template (get_template_args *args)
 static void
 free_get_template (get_template_args *args)
 {
-	g_assert (args);
-	gck_attributes_unref (args->attrs);
+	g_assert (args != NULL);
+	gck_builder_clear (&args->builder);
 	g_free (args);
 }
 
@@ -1254,15 +1228,13 @@ gck_object_get_template (GckObject *self, gulong attr_type,
 
 	ret = _gck_call_sync (self->pv->session, perform_get_template, NULL, &args, cancellable, error);
 
-	_gck_attributes_unlock (args.attrs);
-
 	/* Free any value if failed */
 	if (!ret) {
-		gck_attributes_unref (args.attrs);
-		args.attrs = NULL;
+		gck_builder_clear (&args.builder);
+		return NULL;
 	}
 
-	return args.attrs;
+	return gck_builder_end (&args.builder);
 }
 
 /**
@@ -1322,6 +1294,5 @@ gck_object_get_template_finish (GckObject *self, GAsyncResult *result,
 		return NULL;
 
 	args = _gck_call_arguments (result, get_template_args);
-	_gck_attributes_unlock (args->attrs);
-	return gck_attributes_ref (args->attrs);
+	return gck_builder_end (&args->builder);
 }
diff --git a/gck/gck-private.h b/gck/gck-private.h
index 3926fe1..884be22 100644
--- a/gck/gck-private.h
+++ b/gck/gck-private.h
@@ -39,18 +39,14 @@ G_BEGIN_DECLS
  * ATTRIBUTE INTERNALS
  */
 
-void                _gck_attributes_lock                   (GckAttributes *attrs);
-
-void                _gck_attributes_unlock                 (GckAttributes *attrs);
-
-CK_ATTRIBUTE_PTR    _gck_attributes_prepare_in             (GckAttributes *attrs,
+CK_ATTRIBUTE_PTR    _gck_attributes_commit_out             (GckAttributes *attrs,
                                                              CK_ULONG_PTR n_attrs);
 
-CK_ATTRIBUTE_PTR    _gck_attributes_commit_in              (GckAttributes *attrs,
-                                                             CK_ULONG_PTR n_attrs);
+CK_ATTRIBUTE_PTR    _gck_builder_prepare_in                (GckBuilder *attrs,
+                                                            CK_ULONG_PTR n_attrs);
 
-CK_ATTRIBUTE_PTR    _gck_attributes_commit_out             (GckAttributes *attrs,
-                                                             CK_ULONG_PTR n_attrs);
+CK_ATTRIBUTE_PTR    _gck_builder_commit_in                 (GckBuilder *attrs,
+                                                            CK_ULONG_PTR n_attrs);
 
 /* ----------------------------------------------------------------------------
  * MISC
diff --git a/gck/gck-session.c b/gck/gck-session.c
index 6d3fcb6..6fc0266 100644
--- a/gck/gck-session.c
+++ b/gck/gck-session.c
@@ -1431,9 +1431,7 @@ gck_session_create_object (GckSession *self, GckAttributes *attrs,
 	g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
 	g_return_val_if_fail (attrs != NULL, NULL);
 
-	_gck_attributes_lock (attrs);
 	ret = _gck_call_sync (self, perform_create_object, NULL, &args, cancellable, error);
-	_gck_attributes_unlock (attrs);
 
 	if (!ret)
 		return NULL;
@@ -1463,7 +1461,6 @@ gck_session_create_object_async (GckSession *self, GckAttributes *attrs,
 	g_return_if_fail (attrs);
 
 	args->attrs = gck_attributes_ref (attrs);
-	_gck_attributes_lock (attrs);
 
 	_gck_call_async_ready_go (args, cancellable, callback, user_data);
 }
@@ -1484,7 +1481,6 @@ gck_session_create_object_finish (GckSession *self, GAsyncResult *result, GError
 	CreateObject *args;
 
 	args = _gck_call_arguments (result, CreateObject);
-	_gck_attributes_unlock (args->attrs);
 
 	if (!_gck_call_basic_finish (result, error))
 		return NULL;
@@ -1603,8 +1599,6 @@ gck_session_find_handles (GckSession *self,
 	g_return_val_if_fail (n_handles != NULL, NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	_gck_attributes_lock (match);
-
 	if (_gck_call_sync (self, perform_find_objects, NULL, &args, cancellable, error)) {
 		results = args.objects;
 		*n_handles = args.n_objects;
@@ -1612,7 +1606,6 @@ gck_session_find_handles (GckSession *self,
 	}
 
 	g_free (args.objects);
-	_gck_attributes_unlock (match);
 	return results;
 }
 
@@ -1643,7 +1636,6 @@ gck_session_find_handles_async (GckSession *self,
 	args = _gck_call_async_prep (self, self, perform_find_objects,
 	                             NULL, sizeof (*args), free_find_objects);
 	args->attrs = gck_attributes_ref (match);
-	_gck_attributes_lock (match);
 	_gck_call_async_ready_go (args, cancellable, callback, user_data);
 }
 
@@ -1673,7 +1665,6 @@ gck_session_find_handles_finish (GckSession *self,
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
 	args = _gck_call_arguments (result, FindObjects);
-	_gck_attributes_unlock (args->attrs);
 
 	if (!_gck_call_basic_finish (result, error))
 		return NULL;
@@ -1906,13 +1897,7 @@ gck_session_generate_key_pair_full (GckSession *self,
 	/* Shallow copy of the mechanism structure */
 	memcpy (&args.mechanism, mechanism, sizeof (args.mechanism));
 
-	_gck_attributes_lock (public_attrs);
-	if (public_attrs != private_attrs)
-		_gck_attributes_lock (private_attrs);
 	ret = _gck_call_sync (self, perform_generate_key_pair, NULL, &args, cancellable, error);
-	if (public_attrs != private_attrs)
-		_gck_attributes_unlock (private_attrs);
-	_gck_attributes_unlock (public_attrs);
 
 	if (!ret)
 		return FALSE;
@@ -1955,10 +1940,7 @@ gck_session_generate_key_pair_async (GckSession *self, GckMechanism *mechanism,
 	memcpy (&args->mechanism, mechanism, sizeof (args->mechanism));
 
 	args->public_attrs = gck_attributes_ref (public_attrs);
-	_gck_attributes_lock (public_attrs);
 	args->private_attrs = gck_attributes_ref (private_attrs);
-	if (public_attrs != private_attrs)
-		_gck_attributes_lock (private_attrs);
 
 	_gck_call_async_ready_go (args, cancellable, callback, user_data);
 }
@@ -1989,9 +1971,6 @@ gck_session_generate_key_pair_finish (GckSession *self,
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	args = _gck_call_arguments (result, GenerateKeyPair);
-	_gck_attributes_unlock (args->public_attrs);
-	if (args->public_attrs != args->private_attrs)
-		_gck_attributes_unlock (args->private_attrs);
 
 	if (!_gck_call_basic_finish (result, error))
 		return FALSE;
@@ -2299,9 +2278,7 @@ gck_session_unwrap_key_full (GckSession *self,
 	g_object_get (wrapper, "handle", &args.wrapper, NULL);
 	g_return_val_if_fail (args.wrapper != 0, NULL);
 
-	_gck_attributes_lock (attrs);
 	ret = _gck_call_sync (self, perform_unwrap_key, NULL, &args, cancellable, error);
-	_gck_attributes_unlock (attrs);
 
 	if (!ret)
 		return NULL;
@@ -2351,7 +2328,6 @@ gck_session_unwrap_key_async (GckSession *self,
 	args->attrs = gck_attributes_ref (attrs);
 	args->input = input;
 	args->n_input = n_input;
-	_gck_attributes_lock (attrs);
 
 	_gck_call_async_ready_go (args, cancellable, callback, user_data);
 }
@@ -2375,7 +2351,6 @@ gck_session_unwrap_key_finish (GckSession *self, GAsyncResult *result, GError **
 	g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
 
 	args = _gck_call_arguments (result, UnwrapKey);
-	_gck_attributes_unlock (args->attrs);
 
 	if (!_gck_call_basic_finish (result, error))
 		return NULL;
@@ -2473,9 +2448,7 @@ gck_session_derive_key_full (GckSession *self, GckObject *base, GckMechanism *me
 	g_object_get (base, "handle", &args.key, NULL);
 	g_return_val_if_fail (args.key != 0, NULL);
 
-	_gck_attributes_lock (attrs);
 	ret = _gck_call_sync (self, perform_derive_key, NULL, &args, cancellable, error);
-	_gck_attributes_unlock (attrs);
 
 	if (!ret)
 		return NULL;
@@ -2515,7 +2488,6 @@ gck_session_derive_key_async (GckSession *self, GckObject *base, GckMechanism *m
 	memcpy (&args->mechanism, mechanism, sizeof (args->mechanism));
 
 	args->attrs = gck_attributes_ref (attrs);
-	_gck_attributes_lock (attrs);
 
 	_gck_call_async_ready_go (args, cancellable, callback, user_data);
 }
@@ -2539,7 +2511,6 @@ gck_session_derive_key_finish (GckSession *self, GAsyncResult *result, GError **
 	g_return_val_if_fail (GCK_IS_SESSION (self), NULL);
 
 	args = _gck_call_arguments (result, DeriveKey);
-	_gck_attributes_unlock (args->attrs);
 
 	if (!_gck_call_basic_finish (result, error))
 		return NULL;
diff --git a/gck/gck-uri.c b/gck/gck-uri.c
index 3d66c83..cf9707b 100644
--- a/gck/gck-uri.c
+++ b/gck/gck-uri.c
@@ -199,6 +199,7 @@ GckUriData*
 gck_uri_parse (const gchar *string, GckUriFlags flags, GError **error)
 {
 	GckUriData *uri_data = NULL;
+	GckBuilder builder;
 	CK_ATTRIBUTE_PTR attrs;
 	CK_ULONG i, n_attrs;
 	P11KitUri *p11_uri;
@@ -249,9 +250,10 @@ gck_uri_parse (const gchar *string, GckUriFlags flags, GError **error)
 		uri_data->token_info = _gck_token_info_from_pkcs11 (p11_kit_uri_get_token_info (p11_uri));
 	if (flags & GCK_URI_FOR_OBJECT) {
 		attrs = p11_kit_uri_get_attributes (p11_uri, &n_attrs);
-		uri_data->attributes = gck_attributes_new ();
+		gck_builder_init (&builder);
 		for (i = 0; i < n_attrs; ++i)
-			gck_attributes_add (uri_data->attributes, (GckAttribute*)&attrs[i]);
+			gck_builder_add_data (&builder, attrs[i].type, attrs[i].pValue, attrs[i].ulValueLen);
+		uri_data->attributes = gck_builder_end (&builder);
 	}
 	uri_data->any_unrecognized = p11_kit_uri_any_unrecognized (p11_uri);
 
@@ -272,7 +274,7 @@ gck_uri_parse (const gchar *string, GckUriFlags flags, GError **error)
 gchar*
 gck_uri_build (GckUriData *uri_data, GckUriFlags flags)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	P11KitUri *p11_uri = 0;
 	gchar *string;
 	int res;
@@ -337,8 +339,7 @@ gck_uri_data_copy (GckUriData *uri_data)
 	GckUriData *copy;
 
 	copy = g_memdup (uri_data, sizeof (GckUriData));
-	copy->attributes = gck_attributes_new ();
-	gck_attributes_add_all (copy->attributes, uri_data->attributes);
+	copy->attributes = gck_attributes_ref (uri_data->attributes);
 	copy->module_info = gck_module_info_copy (copy->module_info);
 	copy->token_info = gck_token_info_copy (copy->token_info);
 	return copy;
diff --git a/gck/gck.h b/gck/gck.h
index 44ff840..cbea1c5 100644
--- a/gck/gck.h
+++ b/gck/gck.h
@@ -144,7 +144,7 @@ void                gck_attribute_init_copy                 (GckAttribute *dest,
 GType               gck_attribute_get_type                  (void) G_GNUC_CONST;
 
 GckAttribute*       gck_attribute_new                       (gulong attr_type,
-                                                             gpointer value,
+                                                             const guchar *value,
                                                              gsize length);
 
 GckAttribute*       gck_attribute_new_invalid               (gulong attr_type);
@@ -163,15 +163,15 @@ GckAttribute*       gck_attribute_new_ulong                 (gulong attr_type,
 GckAttribute*       gck_attribute_new_string                (gulong attr_type,
                                                              const gchar *value);
 
-gboolean            gck_attribute_is_invalid                (GckAttribute *attr);
+gboolean            gck_attribute_is_invalid                (const GckAttribute *attr);
 
-gboolean            gck_attribute_get_boolean               (GckAttribute *attr);
+gboolean            gck_attribute_get_boolean               (const GckAttribute *attr);
 
-gulong              gck_attribute_get_ulong                 (GckAttribute *attr);
+gulong              gck_attribute_get_ulong                 (const GckAttribute *attr);
 
-gchar*              gck_attribute_get_string                (GckAttribute *attr);
+gchar*              gck_attribute_get_string                (const GckAttribute *attr);
 
-void                gck_attribute_get_date                  (GckAttribute *attr,
+void                gck_attribute_get_date                  (const GckAttribute *attr,
                                                              GDate* value);
 
 gboolean            gck_attribute_equal                     (gconstpointer attr1,
@@ -179,118 +179,203 @@ gboolean            gck_attribute_equal                     (gconstpointer attr1
 
 guint               gck_attribute_hash                      (gconstpointer attr);
 
-GckAttribute*       gck_attribute_dup                       (GckAttribute *attr);
+GckAttribute*       gck_attribute_dup                       (const GckAttribute *attr);
 
 void                gck_attribute_clear                     (GckAttribute *attr);
 
 void                gck_attribute_free                      (gpointer attr);
 
-void                gck_attribute_dump                      (GckAttribute *attr);
+void                gck_attribute_dump                      (const GckAttribute *attr);
+
+typedef struct _GckBuilder GckBuilder;
+
+struct _GckBuilder {
+	/*< private >*/
+	gsize x[16];
+};
+
+typedef enum {
+	GCK_BUILDER_NONE,
+	GCK_BUILDER_SECURE_MEMORY = 1,
+} GckBuilderFlags;
 
 typedef struct _GckAttributes GckAttributes;
 
-#define             GCK_TYPE_ATTRIBUTES                     (gck_attributes_get_boxed_type ())
+GckBuilder *         gck_builder_new                        (GckBuilderFlags flags);
 
-GType               gck_attributes_get_type                 (void) G_GNUC_CONST;
+#define              GCK_BUILDER_INIT                       { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
 
-GckAttributes*      gck_attributes_new                      (void);
+GckBuilder *         gck_builder_ref                        (GckBuilder *builder);
 
-GckAttributes*      gck_attributes_new_empty                (gulong attr_type,
-                                                             ...);
+void                 gck_builder_unref                      (gpointer builder);
 
-GckAttributes*      gck_attributes_new_full                 (GckAllocator allocator);
+void                 gck_builder_init                       (GckBuilder *builder);
 
-GckAttribute*       gck_attributes_at                       (GckAttributes *attrs,
-                                                             guint index);
+void                 gck_builder_init_full                  (GckBuilder *builder,
+                                                             GckBuilderFlags flags);
 
-GckAttribute*       gck_attributes_add                      (GckAttributes *attrs,
-                                                             GckAttribute *attr);
+#define              GCK_TYPE_BUILDER                       (gck_builder_get_type ())
 
-void                gck_attributes_add_all                  (GckAttributes *attrs,
-                                                             GckAttributes *from);
+GType                gck_builder_get_type                   (void) G_GNUC_CONST;
 
-GckAttribute*       gck_attributes_add_data                 (GckAttributes *attrs,
+void                 gck_builder_take_data                  (GckBuilder *builder,
+                                                             gulong attr_type,
+                                                             guchar *value,
+                                                             gsize length);
+
+void                 gck_builder_add_data                   (GckBuilder *builder,
                                                              gulong attr_type,
                                                              const guchar *value,
                                                              gsize length);
 
-GckAttribute*       gck_attributes_add_invalid              (GckAttributes *attrs,
+void                 gck_builder_add_empty                  (GckBuilder *builder,
                                                              gulong attr_type);
 
-GckAttribute*       gck_attributes_add_empty                (GckAttributes *attrs,
+void                 gck_builder_add_invalid                (GckBuilder *builder,
                                                              gulong attr_type);
 
-GckAttribute*       gck_attributes_add_boolean              (GckAttributes *attrs,
+void                 gck_builder_add_ulong                  (GckBuilder *builder,
+                                                             gulong attr_type,
+                                                             gulong value);
+
+void                 gck_builder_add_boolean                (GckBuilder *builder,
                                                              gulong attr_type,
                                                              gboolean value);
 
-GckAttribute*       gck_attributes_add_string               (GckAttributes *attrs,
+void                 gck_builder_add_date                   (GckBuilder *builder,
+                                                             gulong attr_type,
+                                                             const GDate *value);
+
+void                 gck_builder_add_string                 (GckBuilder *builder,
                                                              gulong attr_type,
                                                              const gchar *value);
 
-GckAttribute*       gck_attributes_add_date                 (GckAttributes *attrs,
+void                 gck_builder_add_attribute              (GckBuilder *builder,
+                                                             const GckAttribute *attr);
+
+void                 gck_builder_add_owned                  (GckBuilder *builder,
+                                                             const GckAttribute *attr);
+
+void                 gck_builder_add_all                    (GckBuilder *builder,
+                                                             GckAttributes *attrs);
+
+void                 gck_builder_add_only                   (GckBuilder *builder,
+                                                             GckAttributes *attrs,
+                                                             gulong only_type,
+                                                             ...);
+
+void                 gck_builder_add_onlyv                  (GckBuilder *builder,
+                                                             GckAttributes *attrs,
+                                                             const gulong *only_types,
+                                                             guint n_only_types);
+
+void                 gck_builder_add_except                 (GckBuilder *builder,
+                                                             GckAttributes *attrs,
+                                                             gulong except_type,
+                                                             ...);
+
+void                 gck_builder_add_exceptv                (GckBuilder *builder,
+                                                             GckAttributes *attrs,
+                                                             const gulong *except_types,
+                                                             guint n_except_types);
+
+void                 gck_builder_set_data                   (GckBuilder *builder,
                                                              gulong attr_type,
-                                                             const GDate *value);
+                                                             const guchar *value,
+                                                             gsize length);
 
-GckAttribute*       gck_attributes_add_ulong                (GckAttributes *attrs,
+void                 gck_builder_set_empty                  (GckBuilder *builder,
+                                                             gulong attr_type);
+
+void                 gck_builder_set_invalid                (GckBuilder *builder,
+                                                             gulong attr_type);
+
+void                 gck_builder_set_ulong                  (GckBuilder *builder,
                                                              gulong attr_type,
                                                              gulong value);
 
-GckAttribute*       gck_attributes_find                     (GckAttributes *attrs,
+void                 gck_builder_set_boolean                (GckBuilder *builder,
+                                                             gulong attr_type,
+                                                             gboolean value);
+
+void                 gck_builder_set_date                   (GckBuilder *builder,
+                                                             gulong attr_type,
+                                                             const GDate *value);
+
+void                 gck_builder_set_string                 (GckBuilder *builder,
+                                                             gulong attr_type,
+                                                             const gchar *value);
+
+void                 gck_builder_set_all                    (GckBuilder *builder,
+                                                             GckAttributes *attrs);
+
+const GckAttribute * gck_builder_find                       (GckBuilder *builder,
                                                              gulong attr_type);
 
-gboolean            gck_attributes_find_boolean             (GckAttributes *attrs,
+gboolean             gck_builder_find_boolean               (GckBuilder *builder,
                                                              gulong attr_type,
                                                              gboolean *value);
 
-gboolean            gck_attributes_find_ulong               (GckAttributes *attrs,
+gboolean             gck_builder_find_ulong                 (GckBuilder *builder,
                                                              gulong attr_type,
                                                              gulong *value);
 
-gboolean            gck_attributes_find_string              (GckAttributes *attrs,
+gboolean             gck_builder_find_string                (GckBuilder *builder,
                                                              gulong attr_type,
                                                              gchar **value);
 
-gboolean            gck_attributes_find_date                (GckAttributes *attrs,
+gboolean             gck_builder_find_date                  (GckBuilder *builder,
                                                              gulong attr_type,
                                                              GDate *value);
 
-void                gck_attributes_set                      (GckAttributes *attrs,
-                                                             GckAttribute *attr);
+GckAttributes *      gck_builder_steal                      (GckBuilder *builder);
 
-void                gck_attributes_set_boolean              (GckAttributes *attrs,
-                                                             gulong attr_type,
-                                                             gboolean value);
+GckAttributes *      gck_builder_end                        (GckBuilder *builder);
 
-void                gck_attributes_set_ulong                (GckAttributes *attrs,
-                                                             gulong attr_type,
-                                                             gulong value);
+GckBuilder *         gck_builder_copy                       (GckBuilder *builder);
+
+void                 gck_builder_clear                      (GckBuilder *builder);
+
+#define              GCK_TYPE_ATTRIBUTES                    (gck_attributes_get_boxed_type ())
+
+GType                gck_attributes_get_type                (void) G_GNUC_CONST;
+
+GckAttributes *      gck_attributes_new_empty               (void);
+
+const GckAttribute * gck_attributes_at                      (GckAttributes *attrs,
+                                                             guint index);
+
+const GckAttribute * gck_attributes_find                    (GckAttributes *attrs,
+                                                             gulong attr_type);
 
-void                gck_attributes_set_string               (GckAttributes *attrs,
+gboolean             gck_attributes_find_boolean            (GckAttributes *attrs,
                                                              gulong attr_type,
-                                                             const gchar *value);
+                                                             gboolean *value);
 
-void                gck_attributes_set_date                 (GckAttributes *attrs,
+gboolean             gck_attributes_find_ulong              (GckAttributes *attrs,
                                                              gulong attr_type,
-                                                             const GDate *value);
+                                                             gulong *value);
 
-void                gck_attributes_set_all                  (GckAttributes *attrs,
-                                                             GckAttributes *from);
+gboolean             gck_attributes_find_string             (GckAttributes *attrs,
+                                                             gulong attr_type,
+                                                             gchar **value);
 
-gulong              gck_attributes_count                    (GckAttributes *attrs);
+gboolean             gck_attributes_find_date               (GckAttributes *attrs,
+                                                             gulong attr_type,
+                                                             GDate *value);
 
-GckAttributes*      gck_attributes_ref                      (GckAttributes *attrs);
+gulong               gck_attributes_count                   (GckAttributes *attrs);
 
-void                gck_attributes_unref                    (gpointer attrs);
+GckAttributes *      gck_attributes_ref                     (GckAttributes *attrs);
 
-gboolean            gck_attributes_contains                 (GckAttributes *attrs,
-                                                             GckAttribute *match);
+void                 gck_attributes_unref                   (gpointer attrs);
 
-GckAttributes *     gck_attributes_dup                      (GckAttributes *attrs);
+gboolean             gck_attributes_contains                (GckAttributes *attrs,
+                                                             const GckAttribute *match);
 
-void                gck_attributes_dump                     (GckAttributes *attrs);
+void                 gck_attributes_dump                    (GckAttributes *attrs);
 
-gchar *             gck_attributes_to_string                (GckAttributes *attrs);
+gchar *              gck_attributes_to_string               (GckAttributes *attrs);
 
 /* -------------------------------------------------------------------------
  * FORWARDS
diff --git a/gck/gck.symbols b/gck/gck.symbols
index 8d18816..69b8ff0 100644
--- a/gck/gck.symbols
+++ b/gck/gck.symbols
@@ -29,20 +29,10 @@ gck_attribute_new_empty
 gck_attribute_new_invalid
 gck_attribute_new_string
 gck_attribute_new_ulong
-gck_attributes_add
-gck_attributes_add_all
-gck_attributes_add_boolean
-gck_attributes_add_data
-gck_attributes_add_date
-gck_attributes_add_empty
-gck_attributes_add_invalid
-gck_attributes_add_string
-gck_attributes_add_ulong
 gck_attributes_at
 gck_attributes_contains
 gck_attributes_count
 gck_attributes_dump
-gck_attributes_dup
 gck_attributes_find
 gck_attributes_find_boolean
 gck_attributes_find_date
@@ -50,18 +40,49 @@ gck_attributes_find_string
 gck_attributes_find_ulong
 gck_attributes_get_boxed_type
 gck_attributes_get_type
-gck_attributes_new
 gck_attributes_new_empty
-gck_attributes_new_full
 gck_attributes_ref
-gck_attributes_set
-gck_attributes_set_all
-gck_attributes_set_boolean
-gck_attributes_set_date
-gck_attributes_set_string
-gck_attributes_set_ulong
 gck_attributes_to_string
 gck_attributes_unref
+gck_builder_add_all
+gck_builder_add_attribute
+gck_builder_add_boolean
+gck_builder_add_data
+gck_builder_add_date
+gck_builder_add_empty
+gck_builder_add_except
+gck_builder_add_exceptv
+gck_builder_add_invalid
+gck_builder_add_only
+gck_builder_add_onlyv
+gck_builder_add_owned
+gck_builder_add_string
+gck_builder_add_ulong
+gck_builder_clear
+gck_builder_copy
+gck_builder_end
+gck_builder_find
+gck_builder_find_boolean
+gck_builder_find_date
+gck_builder_find_string
+gck_builder_find_ulong
+gck_builder_flags_get_type
+gck_builder_get_type
+gck_builder_init
+gck_builder_init_full
+gck_builder_new
+gck_builder_ref
+gck_builder_set_all
+gck_builder_set_boolean
+gck_builder_set_data
+gck_builder_set_date
+gck_builder_set_empty
+gck_builder_set_invalid
+gck_builder_set_string
+gck_builder_set_ulong
+gck_builder_steal
+gck_builder_take_data
+gck_builder_unref
 gck_enumerator_get_chained
 gck_enumerator_get_interaction
 gck_enumerator_get_object_type
diff --git a/gck/tests/test-gck-attributes.c b/gck/tests/test-gck-attributes.c
index 06a8b60..7c287dc 100644
--- a/gck/tests/test-gck-attributes.c
+++ b/gck/tests/test-gck-attributes.c
@@ -26,11 +26,17 @@
 #include <glib.h>
 #include <string.h>
 
+#include "egg/egg-secure-memory.h"
+
 #include "gck/gck.h"
 #include "gck/gck-test.h"
 
+EGG_SECURE_DEFINE_GLIB_GLOBALS ();
+
+EGG_SECURE_DECLARE (test_gck_attributes);
+
 #define ATTR_TYPE 55
-#define ATTR_DATA "TEST DATA"
+#define ATTR_DATA (const guchar *)"TEST DATA"
 #define N_ATTR_DATA ((gsize)9)
 
 static void
@@ -49,52 +55,6 @@ test_init_memory (void)
 }
 
 static void
-test_value_to_boolean (void)
-{
-	CK_BBOOL data = CK_TRUE;
-	gboolean result = FALSE;
-
-	if (!gck_value_to_boolean (&data, sizeof (data), &result))
-		g_assert_not_reached ();
-
-	g_assert (result == TRUE);
-
-	if (!gck_value_to_boolean (&data, sizeof (data), NULL))
-		g_assert_not_reached ();
-
-	/* Should fail */
-	if (gck_value_to_boolean (&data, 0, NULL))
-		g_assert_not_reached ();
-	if (gck_value_to_boolean (&data, 2, NULL))
-		g_assert_not_reached ();
-	if (gck_value_to_boolean (&data, (CK_ULONG)-1, NULL))
-		g_assert_not_reached ();
-}
-
-static void
-test_value_to_ulong (void)
-{
-	CK_ULONG data = 34343;
-	gulong result = 0;
-
-	if (!gck_value_to_ulong ((const guchar *)&data, sizeof (data), &result))
-		g_assert_not_reached ();
-
-	g_assert (result == 34343);
-
-	if (!gck_value_to_ulong ((const guchar *)&data, sizeof (data), NULL))
-		g_assert_not_reached ();
-
-	/* Should fail */
-	if (gck_value_to_ulong ((const guchar *)&data, 0, NULL))
-		g_assert_not_reached ();
-	if (gck_value_to_ulong ((const guchar *)&data, 2, NULL))
-		g_assert_not_reached ();
-	if (gck_value_to_ulong ((const guchar *)&data, (CK_ULONG)-1, NULL))
-		g_assert_not_reached ();
-}
-
-static void
 test_init_boolean (void)
 {
 	GckAttribute attr;
@@ -239,6 +199,7 @@ test_new_ulong (void)
 	gck_attribute_free (attr);
 }
 
+
 static void
 test_new_string (void)
 {
@@ -367,15 +328,651 @@ test_copy_attribute (void)
 }
 
 static void
-test_new_attributes (void)
+builder_add_fixtures (GckBuilder *builder,
+                      guint seed)
+{
+	GDate *date = g_date_new_dmy (11 + seed, 12, 2008);
+	gck_builder_add_boolean (builder, 0UL, (TRUE + seed) % 2);
+	gck_builder_add_ulong (builder, 101UL, 888 + seed);
+	gck_builder_add_string (builder, 202UL, "string");
+	gck_builder_add_date (builder, 303UL, date);
+	g_date_free (date);
+	gck_builder_add_data (builder, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
+	gck_builder_add_invalid (builder, 505UL);
+	gck_builder_add_empty (builder, 606UL);
+}
+
+static void
+test_builder_blank (void)
+{
+	GckBuilder builder;
+
+	gck_builder_init (&builder);
+	g_assert (gck_builder_find (&builder, 88) == NULL);
+	gck_builder_clear (&builder);
+}
+
+static void
+test_build_data (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+
+	gck_builder_add_data (&builder, ATTR_TYPE, (const guchar *)"Hello", 5);
+	attr = gck_builder_find (&builder, ATTR_TYPE);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == 5);
+	g_assert (memcmp (attr->value, "Hello", attr->length) == 0);
+
+	gck_builder_set_data (&builder, ATTR_TYPE, (const guchar *)ATTR_DATA, N_ATTR_DATA);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == N_ATTR_DATA);
+	g_assert (memcmp (attr->value, ATTR_DATA, attr->length) == 0);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == N_ATTR_DATA);
+	g_assert (memcmp (attr->value, ATTR_DATA, attr->length) == 0);
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_data_invalid (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+
+	gck_builder_add_data (&builder, ATTR_TYPE, NULL, GCK_INVALID);
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (gck_attribute_is_invalid (attr));
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_data_secure (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	guchar *memory;
+
+	memory = egg_secure_strdup ("password");
+	gck_builder_add_data (&builder, ATTR_TYPE, memory, 8);
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == 8);
+	g_assert (memcmp (attr->value, "password", attr->length) == 0);
+	g_assert (egg_secure_check (attr->value) == TRUE);
+
+	egg_secure_free (memory);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_take (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	guchar *memory;
+
+	memory = g_memdup (ATTR_DATA, N_ATTR_DATA);
+	gck_builder_take_data (&builder, ATTR_TYPE, memory, N_ATTR_DATA);
+	attrs = gck_builder_end (&builder);
+
+	attr = gck_attributes_at (attrs, 0);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == N_ATTR_DATA);
+	g_assert (memcmp (attr->value, ATTR_DATA, attr->length) == 0);
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_take_invalid (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	gpointer memory;
+
+	/* This memory should be freed */
+	memory = g_strdup ("BLAH");
+	gck_builder_take_data (&builder, ATTR_TYPE, memory, GCK_INVALID);
+
+	/* This memory should be freed */
+	memory = egg_secure_strdup ("BLAH");
+	gck_builder_take_data (&builder, ATTR_TYPE, memory, GCK_INVALID);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (gck_attribute_is_invalid (attr));
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_take_secure (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	guchar *memory;
+
+	memory = egg_secure_strdup ("password");
+	gck_builder_take_data (&builder, ATTR_TYPE, memory, 8);
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == 8);
+	g_assert (memcmp (attr->value, "password", attr->length) == 0);
+	g_assert (egg_secure_check (attr->value) == TRUE);
+
+	gck_attributes_unref (attrs);
+}
+
+
+static void
+test_value_to_boolean (void)
+{
+	CK_BBOOL data = CK_TRUE;
+	gboolean result = FALSE;
+
+	if (!gck_value_to_boolean (&data, sizeof (data), &result))
+		g_assert_not_reached ();
+
+	g_assert (result == TRUE);
+
+	if (!gck_value_to_boolean (&data, sizeof (data), NULL))
+		g_assert_not_reached ();
+
+	/* Should fail */
+	if (gck_value_to_boolean (&data, 0, NULL))
+		g_assert_not_reached ();
+	if (gck_value_to_boolean (&data, 2, NULL))
+		g_assert_not_reached ();
+	if (gck_value_to_boolean (&data, (CK_ULONG)-1, NULL))
+		g_assert_not_reached ();
+}
+
+static void
+test_value_to_ulong (void)
+{
+	CK_ULONG data = 34343;
+	gulong result = 0;
+
+	if (!gck_value_to_ulong ((const guchar *)&data, sizeof (data), &result))
+		g_assert_not_reached ();
+
+	g_assert (result == 34343);
+
+	if (!gck_value_to_ulong ((const guchar *)&data, sizeof (data), NULL))
+		g_assert_not_reached ();
+
+	/* Should fail */
+	if (gck_value_to_ulong ((const guchar *)&data, 0, NULL))
+		g_assert_not_reached ();
+	if (gck_value_to_ulong ((const guchar *)&data, 2, NULL))
+		g_assert_not_reached ();
+	if (gck_value_to_ulong ((const guchar *)&data, (CK_ULONG)-1, NULL))
+		g_assert_not_reached ();
+}
+
+static void
+test_build_boolean (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
+	const GckAttribute *attr;
+	gboolean value;
 
-	attrs = gck_attributes_new ();
+	g_assert (gck_builder_find_boolean (&builder, 5, &value) == FALSE);
+
+	gck_builder_add_boolean (&builder, ATTR_TYPE, FALSE);
+
+	gck_builder_set_invalid (&builder, 5);
+	g_assert (gck_builder_find_boolean (&builder, 5, &value) == FALSE);
+	gck_builder_set_boolean (&builder, 5, TRUE);
+
+	attr = gck_builder_find (&builder, ATTR_TYPE);
+	g_assert (attr != NULL);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_BBOOL));
+	g_assert (*((CK_BBOOL*)attr->value) == CK_FALSE);
+	if (!gck_builder_find_boolean (&builder, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert (value == FALSE);
+
+	gck_builder_set_boolean (&builder, ATTR_TYPE, TRUE);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_BBOOL));
+	g_assert (*((CK_BBOOL*)attr->value) == CK_TRUE);
+	if (!gck_builder_find_boolean (&builder, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert (value == TRUE);
+
+	if (!gck_builder_find_boolean (&builder, 5, &value))
+		g_assert_not_reached ();
+	g_assert (value == TRUE);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr != NULL);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_BBOOL));
+	g_assert (*((CK_BBOOL*)attr->value) == CK_TRUE);
+
+	if (!gck_attributes_find_boolean (attrs, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert (value == TRUE);
+
+	g_assert (gck_attribute_get_boolean (attr) == TRUE);
+
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 2);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_date (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	CK_DATE ck_date;
+	GDate *date, date2;
+
+	g_assert (gck_builder_find_date (&builder, 5, &date2) == FALSE);
+
+	date = g_date_new_dmy(8, 8, 1960);
+	memcpy (ck_date.year, "1960", 4);
+	memcpy (ck_date.month, "08", 2);
+	memcpy (ck_date.day, "08", 2);
+
+	gck_builder_add_date (&builder, ATTR_TYPE, date);
+
+	gck_builder_set_invalid (&builder, 5);
+	g_assert (gck_builder_find_date (&builder, 5, &date2) == FALSE);
+	attr = gck_builder_find (&builder, 5);
+	gck_attribute_get_date (attr, &date2);
+	g_assert_cmpint (date2.day, ==, 0);
+	g_assert_cmpint (date2.month, ==, 0);
+	g_assert_cmpint (date2.year, ==, 0);
+
+	gck_builder_set_date (&builder, 5, date);
+
+	attr = gck_builder_find (&builder, ATTR_TYPE);
+	g_assert (attr != NULL);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_DATE));
+	g_assert (memcmp (attr->value, &ck_date, attr->length) == 0);
+	if (!gck_builder_find_date (&builder, ATTR_TYPE, &date2))
+		g_assert_not_reached ();
+	g_assert (g_date_compare (date, &date2) == 0);
+
+	if (!gck_builder_find_date (&builder, 5, &date2))
+		g_assert_not_reached ();
+	g_assert (g_date_compare (date, &date2) == 0);
+
+	g_date_free (date);
+
+	date = g_date_new_dmy(05, 06, 1960);
+	memcpy (ck_date.year, "1960", 4);
+	memcpy (ck_date.month, "06", 2);
+	memcpy (ck_date.day, "05", 2);
+	gck_builder_set_date (&builder, ATTR_TYPE, date);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_DATE));
+	g_assert (memcmp (attr->value, &ck_date, attr->length) == 0);
+	if (!gck_builder_find_date (&builder, ATTR_TYPE, &date2))
+		g_assert_not_reached ();
+	g_assert (g_date_compare (date, &date2) == 0);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr != NULL);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_DATE));
+	g_assert (memcmp (attr->value, &ck_date, attr->length) == 0);
+
+	gck_attribute_get_date (attr, &date2);
+	g_assert (g_date_compare (date, &date2) == 0);
+
+	g_date_free (date);
+
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 2);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_ulong (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	gulong value;
+
+	g_assert (gck_builder_find_ulong (&builder, 5, &value) == FALSE);
+
+	gck_builder_add_ulong (&builder, ATTR_TYPE, 99);
+
+	gck_builder_set_invalid (&builder, 5);
+	g_assert (gck_builder_find_ulong (&builder, 5, &value) == FALSE);
+	gck_builder_set_ulong (&builder, 5, 292);
+
+	attr = gck_builder_find (&builder, ATTR_TYPE);
+	g_assert (attr != NULL);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_ULONG));
+	g_assert (*((CK_ULONG*)attr->value) == 99);
+	if (!gck_builder_find_ulong (&builder, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert (value == 99);
+
+	gck_builder_set_ulong (&builder, ATTR_TYPE, 88);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_ULONG));
+	g_assert (*((CK_ULONG*)attr->value) == 88);
+	if (!gck_builder_find_ulong (&builder, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert (value == 88);
+
+	if (!gck_builder_find_ulong (&builder, 5, &value))
+		g_assert_not_reached ();
+	g_assert (value == 292);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr != NULL);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == sizeof (CK_ULONG));
+	g_assert (*((CK_ULONG*)attr->value) == 88);
+
+	if (!gck_attributes_find_ulong (attrs, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert (value == 88);
+	g_assert (gck_attribute_get_ulong (attr) == 88);
+
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 2);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_string (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	gchar *value;
+
+	g_assert (gck_builder_find_string (&builder, 5, &value) == FALSE);
+
+	gck_builder_add_string (&builder, ATTR_TYPE, "My my");
+
+	gck_builder_set_invalid (&builder, 5);
+	g_assert (gck_builder_find_string (&builder, 5, &value) == FALSE);
+	gck_builder_set_string (&builder, 5, "Hello");
+
+	attr = gck_builder_find (&builder, ATTR_TYPE);
+	g_assert (attr != NULL);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == strlen ("My my"));
+	g_assert (memcmp (attr->value, "My my", attr->length) == 0);
+
+	if (!gck_builder_find_string (&builder, 5, &value))
+		g_assert_not_reached ();
+	g_assert_cmpstr (value, ==, "Hello");
+	g_free (value);
+
+	gck_builder_set_string (&builder, ATTR_TYPE, "a test string");
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == strlen ("a test string"));
+	g_assert (memcmp (attr->value, "a test string", attr->length) == 0);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr != NULL);
+
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == strlen ("a test string"));
+	g_assert (memcmp (attr->value, "a test string", attr->length) == 0);
+
+	if (!gck_attributes_find_string (attrs, ATTR_TYPE, &value))
+		g_assert_not_reached ();
+	g_assert_cmpstr ("a test string", ==, value);
+	g_free (value);
+
+	value = gck_attribute_get_string (attr);
+	g_assert_cmpstr ("a test string", ==, value);
+	g_free (value);
+
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 2);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_string_null (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+	gchar *value;
+
+	gck_builder_add_string (&builder, ATTR_TYPE, NULL);
+
+	g_assert (gck_builder_find_string (&builder, ATTR_TYPE, &value) == FALSE);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr->value == NULL);
+	g_assert (attr->length == 0);
+
+	value = gck_attribute_get_string (attr);
+	g_assert (value == NULL);
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_invalid (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+
+	gck_builder_add_invalid (&builder, ATTR_TYPE);
+	gck_builder_set_invalid (&builder, ATTR_TYPE);
+	gck_builder_set_invalid (&builder, 5);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == (gulong)-1);
+	g_assert (attr->value == NULL);
+
+	g_assert (gck_attribute_is_invalid (attr));
+
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 2);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_build_empty (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
+
+	gck_builder_add_empty (&builder, ATTR_TYPE);
+	gck_builder_set_empty (&builder, ATTR_TYPE);
+	gck_builder_set_empty (&builder, 5);
+
+	attr = gck_builder_find (&builder, 5);
+	g_assert (attr->type == 5);
+	g_assert (attr->length == 0);
+	g_assert (attr->value == NULL);
+
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == 0);
+	g_assert (attr->value == NULL);
+
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 2);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_builder_secure (void)
+{
+	GckAttributes *attrs;
+	GckBuilder builder;
+	const GckAttribute *attr;
+
+	gck_builder_init_full (&builder, GCK_BUILDER_SECURE_MEMORY);
+
+	gck_builder_add_boolean (&builder, 88, TRUE);
+	attrs = gck_builder_end (&builder);
+	attr = gck_attributes_at (attrs, 0);
+
+	g_assert (egg_secure_check (attr->value));
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_builder_copy (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	GckBuilder *copy;
+	const GckAttribute *attr;
+
+	gck_builder_add_ulong (&builder, ATTR_TYPE, 88);
+	copy = gck_builder_copy (&builder);
+	gck_builder_clear (&builder);
+
+	attrs = gck_builder_end (copy);
+	gck_builder_unref (copy);
+
+	attr = gck_attributes_at (attrs, 0);
+	g_assert (gck_attribute_get_ulong (attr) == 88);
+	g_assert (attr->type == ATTR_TYPE);
+
+	/* Should be able to copy null */
+	copy = gck_builder_copy (NULL);
+	g_assert (copy == NULL);
+
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_builder_refs (void)
+{
+	GckBuilder *builder, *two;
+	gulong check;
+
+	builder = gck_builder_new (GCK_BUILDER_NONE);
+	gck_builder_add_ulong (builder, 88, 99);
+
+	two = gck_builder_ref (builder);
+
+	g_assert (builder == two);
+
+	if (!gck_builder_find_ulong (builder, 88, &check))
+		g_assert_not_reached ();
+	g_assert (check == 99);
+
+	gck_builder_unref (builder);
+
+	if (!gck_builder_find_ulong (two, 88, &check))
+		g_assert_not_reached ();
+	g_assert (check == 99);
+
+	gck_builder_unref (two);
+}
+
+static void
+test_builder_boxed (void)
+{
+	GckBuilder *builder, *two;
+	gulong check;
+
+	builder = gck_builder_new (GCK_BUILDER_NONE);
+	gck_builder_add_ulong (builder, 88, 99);
+
+	two = g_boxed_copy (GCK_TYPE_BUILDER, builder);
+
+	g_assert (builder == two);
+
+	if (!gck_builder_find_ulong (builder, 88, &check))
+		g_assert_not_reached ();
+	g_assert (check == 99);
+
+	g_boxed_free (GCK_TYPE_BUILDER, builder);
+
+	if (!gck_builder_find_ulong (two, 88, &check))
+		g_assert_not_reached ();
+	g_assert (check == 99);
+
+	gck_builder_unref (two);
+}
+
+static void
+test_builder_add_attr (void)
+{
+	GckBuilder bone = GCK_BUILDER_INIT;
+	GckBuilder btwo = GCK_BUILDER_INIT;
+	const GckAttribute *aone, *atwo;
+	GckAttributes *aones, *atwos;
+	gchar *value;
+
+	gck_builder_add_string (&bone, ATTR_TYPE, "blah");
+	aones = gck_builder_end (&bone);
+	aone = gck_attributes_at (aones, 0);
+
+	gck_builder_add_all (&btwo, aones);
+	atwos = gck_builder_end (&btwo);
+	atwo = gck_attributes_at (atwos, 0);
+
+	/* Should be equal, and also share the values */
+	gck_attribute_equal (aone, atwo);
+	g_assert (aone->value == atwo->value);
+
+	gck_attributes_unref (aones);
+
+	value = gck_attribute_get_string (atwo);
+	g_assert_cmpstr (value, ==, "blah");
+	g_free (value);
+
+	gck_attributes_unref (atwos);
+}
+
+static void
+test_attributes_refs (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+
+	attrs = gck_builder_end (&builder);
 	g_assert (attrs != NULL);
 	g_assert (gck_attributes_count (attrs) == 0);
 
-	gck_attributes_ref (attrs);
+	g_assert (gck_attributes_ref (attrs) == attrs);
 	gck_attributes_unref (attrs);
 
 	gck_attributes_unref (attrs);
@@ -389,7 +986,7 @@ test_attributes_contents (GckAttributes *attrs,
                           gboolean extras,
                           gint count)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	gchar *value;
 	GDate date, *check;
 
@@ -440,12 +1037,29 @@ test_attributes_contents (GckAttributes *attrs,
 }
 
 static void
-test_new_empty_attributes (void)
+test_attributes_new_empty (void)
 {
-	GckAttributes *attrs = gck_attributes_new_empty (101UL, 202UL, 303UL, 404UL, GCK_INVALID);
-	GckAttribute *attr;
+	GckAttributes *attrs;
+
+	attrs = gck_attributes_new_empty ();
+	g_assert_cmpuint (gck_attributes_count (attrs), ==, 0);
+	gck_attributes_unref (attrs);
+}
+
+static void
+test_attributes_empty (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
+	const GckAttribute *attr;
 	guint i;
 
+	gck_builder_add_empty (&builder, 101UL);
+	gck_builder_add_empty (&builder, 202UL);
+	gck_builder_add_empty (&builder, 303UL);
+	gck_builder_add_empty (&builder, 404UL);
+	attrs = gck_builder_end (&builder);
+
 	g_assert_cmpuint (gck_attributes_count (attrs), ==, 4);
 	for (i = 0; i < gck_attributes_count (attrs); ++i) {
 		attr = gck_attributes_at (attrs, i);
@@ -458,196 +1072,166 @@ test_new_empty_attributes (void)
 }
 
 static void
-test_add_data_attributes (void)
+test_builder_add_from (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckBuilder two = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
-	GDate *date = g_date_new_dmy (11, 12, 2008);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, 0UL, TRUE);
-	gck_attributes_add_ulong (attrs, 101UL, 888);
-	gck_attributes_add_string (attrs, 202UL, "string");
-	gck_attributes_add_date (attrs, 303UL, date);
-	g_date_free (date);
-	gck_attributes_add_data (attrs, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
-	gck_attributes_add_invalid (attrs, 505UL);
-	gck_attributes_add_empty (attrs, 606UL);
+	guint i;
+
+	builder_add_fixtures (&builder, 0);
+	attrs = gck_builder_end (&builder);
+
+	for (i = 0; i < gck_attributes_count (attrs); i++)
+		gck_builder_add_owned (&two, gck_attributes_at (attrs, i));
+
+	gck_attributes_unref (attrs);
+	attrs = gck_builder_end (&two);
+
 	test_attributes_contents (attrs, TRUE, -1);
 	gck_attributes_unref (attrs);
 }
 
+
 static void
-test_add_attributes (void)
+test_builder_add_all (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckBuilder two = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
-	GckAttribute attr;
 
-	GDate *date = g_date_new_dmy (11, 12, 2008);
-	attrs = gck_attributes_new ();
+	builder_add_fixtures (&builder, 0);
+	attrs = gck_builder_end (&builder);
 
-	gck_attribute_init_boolean (&attr, 0UL, TRUE);
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
-
-	gck_attribute_init_ulong (&attr, 101UL, 888);
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
-	gck_attribute_init_string (&attr, 202UL, "string");
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
-
-	gck_attribute_init_date (&attr, 303UL, date);
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
-	g_date_free (date);
-
-	gck_attribute_init (&attr, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
-
-	gck_attribute_init_invalid (&attr, 505UL);
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
-
-	gck_attribute_init_empty (&attr, 606UL);
-	gck_attributes_add (attrs, &attr);
-	gck_attribute_clear (&attr);
+	gck_builder_add_all (&two, attrs);
+	gck_attributes_unref (attrs);
+	attrs = gck_builder_end (&two);
 
 	test_attributes_contents (attrs, TRUE, -1);
 	gck_attributes_unref (attrs);
 }
 
 static void
-test_add_all_attributes (void)
+test_builder_set_all (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckBuilder two = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
-	GckAttributes *copy;
-	GDate *date = g_date_new_dmy (11, 12, 2008);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, 101UL, 888);
-	gck_attributes_add_string (attrs, 202UL, "string");
-	gck_attributes_add_date (attrs, 303UL, date);
-	g_date_free (date);
-	gck_attributes_add_data (attrs, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
-	gck_attributes_add_invalid (attrs, 505UL);
-	gck_attributes_add_empty (attrs, 606UL);
-	gck_attributes_add_boolean (attrs, 0UL, FALSE);
 
-	copy = gck_attributes_new ();
-	gck_attributes_add_boolean (copy, 0UL, TRUE); /* shouldn't be overriden */
-	gck_attributes_add_all (copy, attrs);
-	test_attributes_contents (copy, TRUE, 8);
+	builder_add_fixtures (&builder, 5);
+	builder_add_fixtures (&two, 0);
+	attrs = gck_builder_end (&two);
+	gck_builder_set_all (&builder, attrs);
+	gck_attributes_unref (attrs);
+	attrs = gck_builder_end (&builder);
 
+	test_attributes_contents (attrs, TRUE, -1);
 	gck_attributes_unref (attrs);
-	gck_attributes_unref (copy);
 }
 
+
 static void
-test_set_attributes (void)
+test_builder_set_blank (void)
 {
-	GckAttributes *attrs;
-	GckAttribute attr;
+	GckBuilder builder;
+	gboolean value;
 
-	GDate *date = g_date_new_dmy (11, 12, 2008);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, 0UL, FALSE);
-	gck_attributes_add_ulong (attrs, 101UL, 999);
-	gck_attributes_add_string (attrs, 202UL, "invalid");
-
-	gck_attribute_init_boolean (&attr, 0UL, TRUE);
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
+	gck_builder_init (&builder);
+	gck_builder_set_boolean (&builder, 5, TRUE);
+	if (!gck_builder_find_boolean (&builder, 5, &value))
+		g_assert_not_reached ();
+	g_assert (value == TRUE);
+	gck_builder_clear (&builder);
+}
 
-	gck_attribute_init_ulong (&attr, 101UL, 888);
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
-	gck_attribute_init_string (&attr, 202UL, "string");
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
+static void
+test_builder_add_only (void)
+{
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckBuilder two = GCK_BUILDER_INIT;
+	GckAttributes *attrs;
 
-	gck_attribute_init_date (&attr, 303UL, date);
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
-	g_date_free (date);
+	builder_add_fixtures (&builder, 0);
+	attrs = gck_builder_end (&builder);
 
-	gck_attribute_init (&attr, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
+	gck_builder_add_only (&two, attrs, 0UL, 202UL, 404UL, 606UL, GCK_INVALID);
+	gck_attributes_unref (attrs);
+	attrs = gck_builder_end (&two);
 
-	gck_attribute_init_invalid (&attr, 505UL);
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
+	g_assert (gck_attributes_find (attrs, 0UL) != NULL);
+	g_assert (gck_attributes_find (attrs, 202UL) != NULL);
+	g_assert (gck_attributes_find (attrs, 404UL) != NULL);
+	g_assert (gck_attributes_find (attrs, 606UL) != NULL);
 
-	gck_attribute_init_empty (&attr, 606UL);
-	gck_attributes_set (attrs, &attr);
-	gck_attribute_clear (&attr);
+	g_assert (gck_attributes_find (attrs, 101UL) == NULL);
+	g_assert (gck_attributes_find (attrs, 303UL) == NULL);
+	g_assert (gck_attributes_find (attrs, 505UL) == NULL);
 
-	test_attributes_contents (attrs, TRUE, -1);
 	gck_attributes_unref (attrs);
 }
 
 static void
-test_set_all_attributes (void)
+test_builder_add_except (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckBuilder two = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
-	GckAttributes *copy;
-	GDate *date = g_date_new_dmy (11, 12, 2008);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, 0UL, TRUE);
-	gck_attributes_add_ulong (attrs, 101UL, 888);
-	gck_attributes_add_string (attrs, 202UL, "string");
-	gck_attributes_add_date (attrs, 303UL, date);
-	g_date_free (date);
-	gck_attributes_add_data (attrs, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
-	gck_attributes_add_invalid (attrs, 505UL);
-	gck_attributes_add_empty (attrs, 606UL);
 
-	copy = gck_attributes_new ();
-	gck_attributes_add_ulong (copy, 0UL, TRUE); /* should be overridden */
-	gck_attributes_set_all (copy, attrs);
-	test_attributes_contents (copy, TRUE, 7);
+	builder_add_fixtures (&builder, 0);
+	attrs = gck_builder_end (&builder);
+
+	gck_builder_add_except (&two, attrs, 0UL, 202UL, 404UL, 606UL, GCK_INVALID);
+	gck_attributes_unref (attrs);
+	attrs = gck_builder_end (&two);
+
+	g_assert (gck_attributes_find (attrs, 0UL) == NULL);
+	g_assert (gck_attributes_find (attrs, 202UL) == NULL);
+	g_assert (gck_attributes_find (attrs, 404UL) == NULL);
+	g_assert (gck_attributes_find (attrs, 606UL) == NULL);
+
+	g_assert (gck_attributes_find (attrs, 101UL) != NULL);
+	g_assert (gck_attributes_find (attrs, 303UL) != NULL);
+	g_assert (gck_attributes_find (attrs, 505UL) != NULL);
 
 	gck_attributes_unref (attrs);
-	gck_attributes_unref (copy);
 }
 
 static void
-test_dup_attributes (void)
+test_builder_add_only_and_except (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
+	GckBuilder two = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
-	GckAttributes *copy;
-	GDate *date = g_date_new_dmy (11, 12, 2008);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, 0UL, TRUE);
-	gck_attributes_add_ulong (attrs, 101UL, 888);
-	gck_attributes_add_string (attrs, 202UL, "string");
-	gck_attributes_add_date (attrs, 303UL, date);
-	g_date_free (date);
-	gck_attributes_add_data (attrs, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
-	gck_attributes_add_invalid (attrs, 505UL);
-	gck_attributes_add_empty (attrs, 606UL);
 
-	copy = gck_attributes_dup (attrs);
+	builder_add_fixtures (&builder, 0);
+	attrs = gck_builder_end (&builder);
+
+	gck_builder_add_only (&two, attrs, 0UL, 101UL, 202UL, 303UL, GCK_INVALID);
+	gck_builder_add_except (&two, attrs, 0UL, 101UL, 202UL, 303UL, GCK_INVALID);
 	gck_attributes_unref (attrs);
+	attrs = gck_builder_end (&two);
 
-	test_attributes_contents (copy, TRUE, -1);
-	gck_attributes_unref (copy);
+	test_attributes_contents (attrs, TRUE, -1);
+	gck_attributes_unref (attrs);
 }
 
 static void
 test_find_attributes (void)
 {
-	GckAttribute *attr;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GDate check, *date = g_date_new_dmy (13, 12, 2008);
+	GckAttributes *attrs;
+	const GckAttribute *attr;
 	gboolean bvalue, ret;
 	gulong uvalue;
 	gchar *svalue;
 
-	GckAttributes *attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, 0UL, TRUE);
-	gck_attributes_add_ulong (attrs, 101UL, 888UL);
-	gck_attributes_add_string (attrs, 202UL, "string");
-	gck_attributes_add_date (attrs, 303UL, date);
-	gck_attributes_add_data (attrs, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
+	gck_builder_add_boolean (&builder, 0UL, TRUE);
+	gck_builder_add_ulong (&builder, 101UL, 888UL);
+	gck_builder_add_string (&builder, 202UL, "string");
+	gck_builder_add_date (&builder, 303UL, date);
+	gck_builder_add_data (&builder, 404UL, (const guchar *)ATTR_DATA, N_ATTR_DATA);
+	attrs = gck_builder_end (&builder);
 
 	attr = gck_attributes_find (attrs, 404);
 	g_assert (attr != NULL);
@@ -679,38 +1263,60 @@ test_find_attributes (void)
 int
 main (int argc, char **argv)
 {
+	g_type_init ();
 	g_test_init (&argc, &argv, NULL);
 
-	g_test_add_func ("/gck/attributes/init_memory", test_init_memory);
-	g_test_add_func ("/gck/attributes/value_to_boolean", test_value_to_boolean);
-	g_test_add_func ("/gck/attributes/value_to_ulong", test_value_to_ulong);
-	g_test_add_func ("/gck/attributes/init_boolean", test_init_boolean);
-	g_test_add_func ("/gck/attributes/init_date", test_init_date);
-	g_test_add_func ("/gck/attributes/init_ulong", test_init_ulong);
-	g_test_add_func ("/gck/attributes/init_string", test_init_string);
-	g_test_add_func ("/gck/attributes/init_invalid", test_init_invalid);
-	g_test_add_func ("/gck/attributes/init_empty", test_init_empty);
-	g_test_add_func ("/gck/attributes/new_memory", test_new_memory);
-	g_test_add_func ("/gck/attributes/new_boolean", test_new_boolean);
-	g_test_add_func ("/gck/attributes/new_date", test_new_date);
-	g_test_add_func ("/gck/attributes/new_ulong", test_new_ulong);
-	g_test_add_func ("/gck/attributes/new_string", test_new_string);
-	g_test_add_func ("/gck/attributes/new_invalid", test_new_invalid);
-	g_test_add_func ("/gck/attributes/new_empty", test_new_empty);
-	g_test_add_func ("/gck/attributes/get_boolean", test_get_boolean);
-	g_test_add_func ("/gck/attributes/get_date", test_get_date);
-	g_test_add_func ("/gck/attributes/get_ulong", test_get_ulong);
-	g_test_add_func ("/gck/attributes/get_string", test_get_string);
-	g_test_add_func ("/gck/attributes/dup_attribute", test_dup_attribute);
-	g_test_add_func ("/gck/attributes/copy_attribute", test_copy_attribute);
-	g_test_add_func ("/gck/attributes/new_attributes", test_new_attributes);
-	g_test_add_func ("/gck/attributes/new_empty_attributes", test_new_empty_attributes);
-	g_test_add_func ("/gck/attributes/add_data_attributes", test_add_data_attributes);
-	g_test_add_func ("/gck/attributes/add_attributes", test_add_attributes);
-	g_test_add_func ("/gck/attributes/add_all_attributes", test_add_all_attributes);
-	g_test_add_func ("/gck/attributes/set_attributes", test_set_attributes);
-	g_test_add_func ("/gck/attributes/set_all_attributes", test_set_all_attributes);
-	g_test_add_func ("/gck/attributes/dup_attributes", test_dup_attributes);
+	g_test_add_func ("/gck/value/to_boolean", test_value_to_boolean);
+	g_test_add_func ("/gck/value/to_ulong", test_value_to_ulong);
+	g_test_add_func ("/gck/attribute/init_memory", test_init_memory);
+	g_test_add_func ("/gck/attribute/init_boolean", test_init_boolean);
+	g_test_add_func ("/gck/attribute/init_date", test_init_date);
+	g_test_add_func ("/gck/attribute/init_ulong", test_init_ulong);
+	g_test_add_func ("/gck/attribute/init_string", test_init_string);
+	g_test_add_func ("/gck/attribute/init_invalid", test_init_invalid);
+	g_test_add_func ("/gck/attribute/init_empty", test_init_empty);
+	g_test_add_func ("/gck/attribute/new_memory", test_new_memory);
+	g_test_add_func ("/gck/attribute/new_boolean", test_new_boolean);
+	g_test_add_func ("/gck/attribute/new_date", test_new_date);
+	g_test_add_func ("/gck/attribute/new_ulong", test_new_ulong);
+	g_test_add_func ("/gck/attribute/new_string", test_new_string);
+	g_test_add_func ("/gck/attribute/new_invalid", test_new_invalid);
+	g_test_add_func ("/gck/attribute/new_empty", test_new_empty);
+	g_test_add_func ("/gck/attribute/get_boolean", test_get_boolean);
+	g_test_add_func ("/gck/attribute/get_date", test_get_date);
+	g_test_add_func ("/gck/attribute/get_ulong", test_get_ulong);
+	g_test_add_func ("/gck/attribute/get_string", test_get_string);
+	g_test_add_func ("/gck/attribute/dup_attribute", test_dup_attribute);
+	g_test_add_func ("/gck/attribute/copy_attribute", test_copy_attribute);
+	g_test_add_func ("/gck/builder/blank", test_builder_blank);
+	g_test_add_func ("/gck/builder/data", test_build_data);
+	g_test_add_func ("/gck/builder/data-invalid", test_build_data_invalid);
+	g_test_add_func ("/gck/builder/data-secure", test_build_data_secure);
+	g_test_add_func ("/gck/builder/take", test_build_take);
+	g_test_add_func ("/gck/builder/take-invalid", test_build_take_invalid);
+	g_test_add_func ("/gck/builder/take-secure", test_build_take_secure);
+	g_test_add_func ("/gck/builder/boolean", test_build_boolean);
+	g_test_add_func ("/gck/builder/date", test_build_date);
+	g_test_add_func ("/gck/builder/ulong", test_build_ulong);
+	g_test_add_func ("/gck/builder/string", test_build_string);
+	g_test_add_func ("/gck/builder/string-null", test_build_string_null);
+	g_test_add_func ("/gck/builder/invalid", test_build_invalid);
+	g_test_add_func ("/gck/builder/empty", test_build_empty);
+	g_test_add_func ("/gck/builder/secure", test_builder_secure);
+	g_test_add_func ("/gck/builder/copy", test_builder_copy);
+	g_test_add_func ("/gck/builder/refs", test_builder_refs);
+	g_test_add_func ("/gck/builder/boxed", test_builder_boxed);
+	g_test_add_func ("/gck/builder/add-attr", test_builder_add_attr);
+	g_test_add_func ("/gck/builder/add-all", test_builder_add_all);
+	g_test_add_func ("/gck/builder/add-from", test_builder_add_from);
+	g_test_add_func ("/gck/builder/add-only", test_builder_add_only);
+	g_test_add_func ("/gck/builder/add-except", test_builder_add_except);
+	g_test_add_func ("/gck/builder/add-only-and-except", test_builder_add_only_and_except);
+	g_test_add_func ("/gck/builder/set-all", test_builder_set_all);
+	g_test_add_func ("/gck/builder/set-blank", test_builder_set_blank);
+	g_test_add_func ("/gck/attributes/refs", test_attributes_refs);
+	g_test_add_func ("/gck/attributes/new-empty", test_attributes_new_empty);
+	g_test_add_func ("/gck/attributes/empty", test_attributes_empty);
 	g_test_add_func ("/gck/attributes/find_attributes", test_find_attributes);
 
 	return g_test_run ();
diff --git a/gck/tests/test-gck-crypto.c b/gck/tests/test-gck-crypto.c
index 241b208..8a8914d 100644
--- a/gck/tests/test-gck-crypto.c
+++ b/gck/tests/test-gck-crypto.c
@@ -102,6 +102,7 @@ fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data)
 static GckObject*
 find_key (GckSession *session, CK_ATTRIBUTE_TYPE method, CK_MECHANISM_TYPE mech)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GList *objects, *l;
 	GckAttributes *attrs;
 	GckObject *object = NULL;
@@ -109,8 +110,8 @@ find_key (GckSession *session, CK_ATTRIBUTE_TYPE method, CK_MECHANISM_TYPE mech)
 	gboolean match;
 	gsize n_mechs;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, method, TRUE);
+	gck_builder_add_boolean (&builder, method, TRUE);
+	attrs = gck_builder_end (&builder);
 	objects = gck_session_find_objects (session, attrs, NULL, NULL);
 	gck_attributes_unref (attrs);
 	g_assert (objects);
@@ -141,12 +142,13 @@ find_key (GckSession *session, CK_ATTRIBUTE_TYPE method, CK_MECHANISM_TYPE mech)
 static GckObject*
 find_key_with_value (GckSession *session, const gchar *value)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GList *objects;
 	GckAttributes *attrs;
 	GckObject *object;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_string (attrs, CKA_VALUE, value);
+	gck_builder_add_string (&builder, CKA_VALUE, value);
+	attrs = gck_builder_end (&builder);
 	objects = gck_session_find_objects (session, attrs, NULL, NULL);
 	gck_attributes_unref (attrs);
 	g_assert (objects);
@@ -160,7 +162,7 @@ static void
 check_key_with_value (GckSession *session, GckObject *key, CK_OBJECT_CLASS klass, const gchar *value)
 {
 	GckAttributes *attrs;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	gulong check;
 
 	attrs = gck_object_get (key, NULL, NULL, CKA_CLASS, CKA_VALUE, GCK_INVALID);
@@ -397,16 +399,17 @@ static void
 test_generate_key_pair (Test *test, gconstpointer unused)
 {
 	GckMechanism mech = { CKM_MOCK_GENERATE, (guchar *)"generate", 9 };
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *pub_attrs, *prv_attrs;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GckObject *pub_key, *prv_key;
 	gboolean ret;
 
-	pub_attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
-	prv_attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (prv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
+	pub_attrs =  gck_builder_end (&builder);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	prv_attrs =  gck_builder_end (&builder);
 
 	/* Full One*/
 	ret = gck_session_generate_key_pair_full (test->session, &mech, pub_attrs, prv_attrs,
@@ -531,14 +534,15 @@ static void
 test_unwrap_key (Test *test, gconstpointer unused)
 {
 	GckMechanism mech = { CKM_MOCK_WRAP, (guchar *)"wrap", 4 };
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GckObject *wrapper, *unwrapped;
 	GckAttributes *attrs;
 
 	wrapper = find_key (test->session, CKA_UNWRAP, 0);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_SECRET_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
+	attrs = gck_builder_end (&builder);
 
 	/* Full One*/
 	unwrapped = gck_session_unwrap_key_full (test->session, wrapper, &mech, (const guchar *)"special", 7, attrs, NULL, &error);
@@ -586,14 +590,15 @@ static void
 test_derive_key (Test *test, gconstpointer unused)
 {
 	GckMechanism mech = { CKM_MOCK_DERIVE, (guchar *)"derive", 6 };
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GckObject *wrapper, *derived;
 	GckAttributes *attrs;
 
 	wrapper = find_key (test->session, CKA_DERIVE, 0);
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_SECRET_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
+	attrs = gck_builder_end (&builder);
 
 	/* Full One*/
 	derived = gck_session_derive_key_full (test->session, wrapper, &mech, attrs, NULL, &error);
diff --git a/gck/tests/test-gck-enumerator.c b/gck/tests/test-gck-enumerator.c
index 0c8496d..42e59b2 100644
--- a/gck/tests/test-gck-enumerator.c
+++ b/gck/tests/test-gck-enumerator.c
@@ -231,6 +231,7 @@ static void
 test_enumerate_session (Test *test,
                         gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckEnumerator *en;
 	GckAttributes *attrs;
 	GError *error = NULL;
@@ -244,7 +245,7 @@ test_enumerate_session (Test *test,
 	session = gck_session_open (slots->data, 0, NULL, NULL, &error);
 	g_assert_no_error (error);
 
-	attrs = gck_attributes_new ();
+	attrs = gck_builder_end (&builder);
 	en = gck_session_enumerate_objects (session, attrs);
 	g_assert (GCK_IS_ENUMERATOR (en));
 	gck_attributes_unref (attrs);
@@ -261,14 +262,15 @@ test_enumerate_session (Test *test,
 static void
 test_attribute_match (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckUriData *uri_data;
 	GError *error = NULL;
 	GckEnumerator *en;
 	GList *objects;
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_string (uri_data->attributes, CKA_LABEL, "Private Capitalize Key");
+	gck_builder_add_string (&builder, CKA_LABEL, "Private Capitalize Key");
+	uri_data->attributes = gck_builder_end (&builder);
 	en = _gck_enumerator_new_for_modules (test->modules, 0, uri_data);
 	g_assert (GCK_IS_ENUMERATOR (en));
 
@@ -548,6 +550,7 @@ static void
 test_chained (Test *test,
               gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckEnumerator *one;
 	GckEnumerator *two;
 	GckEnumerator *three;
@@ -556,19 +559,19 @@ test_chained (Test *test,
 	GList *objects;
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
+	uri_data->attributes = gck_builder_end (&builder);
 	one = _gck_enumerator_new_for_modules (test->modules, 0, uri_data);
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	uri_data->attributes = gck_builder_end (&builder);
 	two = _gck_enumerator_new_for_modules (test->modules, 0, uri_data);
 	gck_enumerator_set_chained (one, two);
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_DATA);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	uri_data->attributes = gck_builder_end (&builder);
 	three = _gck_enumerator_new_for_modules (test->modules, 0, uri_data);
 	gck_enumerator_set_chained (two, three);
 
diff --git a/gck/tests/test-gck-modules.c b/gck/tests/test-gck-modules.c
index 0c3494e..166abbc 100644
--- a/gck/tests/test-gck-modules.c
+++ b/gck/tests/test-gck-modules.c
@@ -65,13 +65,14 @@ teardown (Test *test, gconstpointer unused)
 static void
 test_enumerate_objects (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
 	GError *error = NULL;
 	GckEnumerator *en;
 	GList *objects;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_string (attrs, CKA_LABEL, "Private Capitalize Key");
+	gck_builder_add_string (&builder, CKA_LABEL, "Private Capitalize Key");
+	attrs = gck_builder_end (&builder);
 	en = gck_modules_enumerate_objects (test->modules, attrs, 0);
 	g_assert (GCK_IS_ENUMERATOR (en));
 	gck_attributes_unref (attrs);
diff --git a/gck/tests/test-gck-object.c b/gck/tests/test-gck-object.c
index 43db29a..14493d1 100644
--- a/gck/tests/test-gck-object.c
+++ b/gck/tests/test-gck-object.c
@@ -142,17 +142,18 @@ fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data)
 static void
 test_create_object (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GAsyncResult *result = NULL;
 	GckAttributes *attrs;
 	GckObject *object;
 	CK_OBJECT_HANDLE last_handle;
 	GError *err = NULL;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_string (attrs, CKA_LABEL, "TEST LABEL");
-	gck_attributes_add_boolean (attrs, CKA_TOKEN, CK_FALSE);
-	gck_attributes_add_data (attrs, CKA_VALUE, (const guchar *)"BLAH", 4);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_string (&builder, CKA_LABEL, "TEST LABEL");
+	gck_builder_add_boolean (&builder, CKA_TOKEN, CK_FALSE);
+	gck_builder_add_data (&builder, CKA_VALUE, (const guchar *)"BLAH", 4);
+	attrs = gck_builder_end (&builder);
 
 	object = gck_session_create_object (test->session, attrs, NULL, &err);
 	g_assert (GCK_IS_OBJECT (object));
@@ -180,16 +181,17 @@ test_create_object (Test *test, gconstpointer unused)
 static void
 test_destroy_object (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GAsyncResult *result = NULL;
 	GckAttributes *attrs;
 	GckObject *object;
 	GError *err = NULL;
 	gboolean ret;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_string (attrs, CKA_LABEL, "TEST OBJECT");
-	gck_attributes_add_boolean (attrs, CKA_TOKEN, CK_TRUE);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_string (&builder, CKA_LABEL, "TEST OBJECT");
+	gck_builder_add_boolean (&builder, CKA_TOKEN, CK_TRUE);
+	attrs = gck_builder_end (&builder);
 
 	/* Using simple */
 	object = gck_session_create_object (test->session, attrs, NULL, &err);
@@ -309,6 +311,7 @@ test_get_data_attribute (Test *test, gconstpointer unused)
 static void
 test_set_attributes (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GAsyncResult *result = NULL;
 	GckAttributes *attrs, *templ;
 	GError *err = NULL;
@@ -316,9 +319,9 @@ test_set_attributes (Test *test, gconstpointer unused)
 	gchar *value = NULL;
 	gboolean ret;
 
-	templ = gck_attributes_new ();
-	gck_attributes_add_ulong (templ, CKA_CLASS, 6);
-	gck_attributes_add_string (templ, CKA_LABEL, "CHANGE TWO");
+	gck_builder_add_ulong (&builder, CKA_CLASS, 6);
+	gck_builder_add_string (&builder, CKA_LABEL, "CHANGE TWO");
+	templ = gck_builder_end (&builder);
 
 	/* Full */
 	ret = gck_object_set (test->object, templ, NULL, &err);
@@ -331,9 +334,9 @@ test_set_attributes (Test *test, gconstpointer unused)
 	g_free (value); value = NULL;
 	gck_attributes_unref (attrs);
 
-	templ = gck_attributes_new ();
-	gck_attributes_add_ulong (templ, CKA_CLASS, 7);
-	gck_attributes_add_string (templ, CKA_LABEL, "CHANGE THREE");
+	gck_builder_add_ulong (&builder, CKA_CLASS, 7);
+	gck_builder_add_string (&builder, CKA_LABEL, "CHANGE THREE");
+	templ = gck_builder_end (&builder);
 
 	/* Async */
 	gck_object_set_async (test->object, templ, NULL, fetch_async_result, &result);
@@ -355,29 +358,30 @@ test_set_attributes (Test *test, gconstpointer unused)
 static void
 test_find_objects (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GAsyncResult *result = NULL;
 	GckAttributes *templ, *attrs;
 	GList *objects;
 	GckObject *testobj;
 	GError *err = NULL;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_string (attrs, CKA_LABEL, "UNIQUE LABEL");
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_string (&builder, CKA_LABEL, "UNIQUE LABEL");
+	attrs = gck_builder_end (&builder);
 	testobj = gck_session_create_object (test->session, attrs, NULL, &err);
 	gck_attributes_unref (attrs);
 	g_object_unref (testobj);
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_string (attrs, CKA_LABEL, "OTHER LABEL");
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_string (&builder, CKA_LABEL, "OTHER LABEL");
+	attrs = gck_builder_end (&builder);
 	testobj = gck_session_create_object (test->session, attrs, NULL, &err);
 	gck_attributes_unref (attrs);
 	g_object_unref (testobj);
 
 	/* Simple, "TEST LABEL" */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_string (attrs, CKA_LABEL, "UNIQUE LABEL");
+	gck_builder_add_string (&builder, CKA_LABEL, "UNIQUE LABEL");
+	attrs = gck_builder_end (&builder);
 	objects = gck_session_find_objects (test->session, attrs, NULL, &err);
 	g_assert_no_error (err);
 	g_assert (g_list_length (objects) == 1);
@@ -385,14 +389,16 @@ test_find_objects (Test *test, gconstpointer unused)
 	gck_attributes_unref (attrs);
 
 	/* Full, All */
-	templ = gck_attributes_new ();
+	templ = gck_builder_end (&builder);
 	objects = gck_session_find_objects (test->session, templ, NULL, &err);
 	g_assert_no_error (err);
 	g_assert (g_list_length (objects) > 1);
 	gck_list_unref_free (objects);
+	gck_attributes_unref (templ);
 
 	/* Async, None */
-	gck_attributes_add_string (templ, CKA_LABEL, "blah blah");
+	gck_builder_add_string (&builder, CKA_LABEL, "blah blah");
+	templ = gck_builder_end (&builder);
 	gck_session_find_objects_async (test->session, templ, NULL, fetch_async_result, &result);
 	egg_test_wait_until (500);
 	g_assert (result != NULL);
diff --git a/gck/tests/test-gck-session.c b/gck/tests/test-gck-session.c
index 8e88422..4896063 100644
--- a/gck/tests/test-gck-session.c
+++ b/gck/tests/test-gck-session.c
@@ -428,6 +428,7 @@ authenticate_token (GckModule *module, GckSlot *slot, gchar *label, gchar **pass
 static void
 test_auto_login (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckObject *object;
 	GckSession *new_session;
 	GAsyncResult *result = NULL;
@@ -435,10 +436,10 @@ test_auto_login (Test *test, gconstpointer unused)
 	GckAttributes *attrs;
 	gboolean ret;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_string (attrs, CKA_LABEL, "TEST OBJECT");
-	gck_attributes_add_boolean (attrs, CKA_PRIVATE, CK_TRUE);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_string (&builder, CKA_LABEL, "TEST OBJECT");
+	gck_builder_add_boolean (&builder, CKA_PRIVATE, CK_TRUE);
+	attrs = gck_builder_end (&builder);
 
 	/* Try to do something that requires a login */
 	object = gck_session_create_object (test->session, attrs, NULL, &err);
diff --git a/gck/tests/test-gck-uri.c b/gck/tests/test-gck-uri.c
index b42cc6c..773c665 100644
--- a/gck/tests/test-gck-uri.c
+++ b/gck/tests/test-gck-uri.c
@@ -113,7 +113,7 @@ static void
 test_parse_with_id (void)
 {
 	GError *error = NULL;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	GckUriData *uri_data;
 
 	uri_data = gck_uri_parse ("pkcs11:id=%54%45%53%54%00", GCK_URI_FOR_OBJECT, &error);
@@ -315,18 +315,19 @@ test_build_with_token_empty_info (void)
 static void
 test_build_with_attributes (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	gchar *uri = NULL;
 	GckUriData uri_data;
 	GckUriData *check;
 	gchar *string;
 	gulong value;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 
 	memset (&uri_data, 0, sizeof (uri_data));
-	uri_data.attributes = gck_attributes_new ();
-	gck_attributes_add_string (uri_data.attributes, CKA_LABEL, "The Label");
-	gck_attributes_add_ulong (uri_data.attributes, CKA_CLASS, CKO_DATA);
-	gck_attributes_add_data (uri_data.attributes, CKA_ID, (const guchar *)"TEST", 5);
+	gck_builder_add_string (&builder, CKA_LABEL, "The Label");
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_DATA);
+	gck_builder_add_data (&builder, CKA_ID, (const guchar *)"TEST", 5);
+	uri_data.attributes = gck_builder_end (&builder);
 
 	uri = gck_uri_build (&uri_data, GCK_URI_FOR_OBJECT);
 	g_assert (uri);
@@ -422,12 +423,13 @@ test_parse_unknown_objecttype (void)
 static void
 test_build_objecttype_cert (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckUriData *uri_data;
 	gchar *uri;
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	uri_data->attributes = gck_builder_end (&builder);
 
 	uri = gck_uri_build (uri_data, GCK_URI_FOR_OBJECT);
 	g_assert (uri);
@@ -440,12 +442,13 @@ test_build_objecttype_cert (void)
 static void
 test_build_objecttype_private (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckUriData *uri_data;
 	gchar *uri;
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	uri_data->attributes = gck_builder_end (&builder);
 
 	uri = gck_uri_build (uri_data, GCK_URI_FOR_OBJECT);
 	g_assert (uri);
@@ -458,12 +461,13 @@ test_build_objecttype_private (void)
 static void
 test_build_objecttype_public (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckUriData *uri_data;
 	gchar *uri;
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
+	uri_data->attributes = gck_builder_end (&builder);
 
 	uri = gck_uri_build (uri_data, GCK_URI_FOR_OBJECT);
 	g_assert (uri);
@@ -476,12 +480,13 @@ test_build_objecttype_public (void)
 static void
 test_build_objecttype_secret (void)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckUriData *uri_data;
 	gchar *uri;
 
 	uri_data = gck_uri_data_new ();
-	uri_data->attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_SECRET_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
+	uri_data->attributes = gck_builder_end (&builder);
 
 	uri = gck_uri_build (uri_data, GCK_URI_FOR_OBJECT);
 	g_assert (uri);
diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols
index e1a1dde..4061745 100644
--- a/gcr/gcr-base.symbols
+++ b/gcr/gcr-base.symbols
@@ -177,3 +177,4 @@ gcr_union_collection_new
 gcr_union_collection_remove
 gcr_union_collection_size
 gcr_union_collection_take
+SECMEM_pool_data_v1_0
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index b3314f1..79b42f0 100644
--- a/gcr/gcr-certificate-renderer.c
+++ b/gcr/gcr-certificate-renderer.c
@@ -417,6 +417,7 @@ static void
 gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *registered;
 
 	_gcr_oids_init ();
@@ -460,8 +461,8 @@ gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
 	gcr_certificate_mixin_class_init (gobject_class);
 
 	/* Register this as a renderer which can be loaded */
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	registered = gck_builder_end (&builder);
 	gcr_renderer_register (GCR_TYPE_CERTIFICATE_RENDERER, registered);
 	gck_attributes_unref (registered);
 }
@@ -632,7 +633,7 @@ gcr_certificate_renderer_get_der_data (GcrCertificate *cert,
                                        gsize *n_data)
 {
 	GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (cert);
-	GckAttribute *attr;
+	const GckAttribute *attr;
 
 	g_assert (n_data);
 
diff --git a/gcr/gcr-certificate-request-renderer.c b/gcr/gcr-certificate-request-renderer.c
index c5b7b02..591dd79 100644
--- a/gcr/gcr-certificate-request-renderer.c
+++ b/gcr/gcr-certificate-request-renderer.c
@@ -168,6 +168,7 @@ static void
 _gcr_certificate_request_renderer_class_init (GcrCertificateRequestRendererClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *registered;
 
 	_gcr_oids_init ();
@@ -193,20 +194,21 @@ _gcr_certificate_request_renderer_class_init (GcrCertificateRequestRendererClass
 	 *
 	 * The label to display.
 	 */
+
 	g_object_class_install_property (gobject_class, PROP_LABEL,
 	           g_param_spec_string ("label", "Label", "Certificate Label",
 	                                "", G_PARAM_READWRITE));
 
 	/* Register this as a renderer which can be loaded */
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_CERTIFICATE_REQUEST);
-	gck_attributes_add_ulong (registered, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_PKCS10);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_GCR_CERTIFICATE_REQUEST);
+	gck_builder_add_ulong (&builder, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_PKCS10);
+	registered = gck_builder_end (&builder);
 	gcr_renderer_register (GCR_TYPE_CERTIFICATE_REQUEST_RENDERER, registered);
 	gck_attributes_unref (registered);
 
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_CERTIFICATE_REQUEST);
-	gck_attributes_add_ulong (registered, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_SPKAC);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_GCR_CERTIFICATE_REQUEST);
+	gck_builder_add_ulong (&builder, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_SPKAC);
+	registered = gck_builder_end (&builder);
 	gcr_renderer_register (GCR_TYPE_CERTIFICATE_REQUEST_RENDERER, registered);
 	gck_attributes_unref (registered);
 }
@@ -486,7 +488,7 @@ void
 _gcr_certificate_request_renderer_set_attributes (GcrCertificateRequestRenderer *self,
                                               GckAttributes *attrs)
 {
-	GckAttribute *value;
+	const GckAttribute *value;
 	GNode *asn = NULL;
 	gulong type = 0;
 	EggBytes *bytes;
diff --git a/gcr/gcr-gnupg-importer.c b/gcr/gcr-gnupg-importer.c
index 29f902c..351ac46 100644
--- a/gcr/gcr-gnupg-importer.c
+++ b/gcr/gcr-gnupg-importer.c
@@ -213,6 +213,7 @@ static void
 _gcr_gnupg_importer_class_init (GcrGnupgImporterClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *registered;
 
 	gobject_class->dispose = _gcr_gnupg_importer_dispose;
@@ -236,8 +237,8 @@ _gcr_gnupg_importer_class_init (GcrGnupgImporterClass *klass)
 	           g_param_spec_string ("directory", "Directory", "Directory to import keys to",
 	                                NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
+	registered = gck_builder_end (&builder);
 	gcr_importer_register (GCR_TYPE_GNUPG_IMPORTER, registered);
 	gck_attributes_unref (registered);
 
diff --git a/gcr/gcr-gnupg-renderer.c b/gcr/gcr-gnupg-renderer.c
index 7040577..9f31eb0 100644
--- a/gcr/gcr-gnupg-renderer.c
+++ b/gcr/gcr-gnupg-renderer.c
@@ -163,6 +163,7 @@ static void
 _gcr_gnupg_renderer_class_init (GcrGnupgRendererClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *registered;
 
 	_gcr_gnupg_renderer_parent_class = g_type_class_peek_parent (klass);
@@ -185,8 +186,8 @@ _gcr_gnupg_renderer_class_init (GcrGnupgRendererClass *klass)
 	                                "", G_PARAM_READWRITE));
 
 	/* Register this as a renderer which can be loaded */
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
+	registered = gck_builder_end (&builder);
 	gcr_renderer_register (GCR_TYPE_GNUPG_RENDERER, registered);
 	gck_attributes_unref (registered);
 }
@@ -827,7 +828,7 @@ void
 _gcr_gnupg_renderer_set_attributes (GcrGnupgRenderer *self,
                                     GckAttributes *attrs)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	GPtrArray *records;
 
 	g_return_if_fail (GCR_IS_GNUPG_RENDERER (self));
diff --git a/gcr/gcr-import-interaction.c b/gcr/gcr-import-interaction.c
index 19d0bc0..0c5a293 100644
--- a/gcr/gcr-import-interaction.c
+++ b/gcr/gcr-import-interaction.c
@@ -81,7 +81,7 @@ gcr_import_interaction_default_init (GcrImportInteractionIface *iface)
 /**
  * gcr_import_interaction_supplement_prep:
  * @interaction: the interaction
- * @attributes: attributes to supplement
+ * @builder: attributes to supplement
  *
  * Prepare for supplementing the given attributes before import. This means
  * prompting the user for things like labels and the like. The attributes
@@ -93,22 +93,22 @@ gcr_import_interaction_default_init (GcrImportInteractionIface *iface)
  */
 void
 gcr_import_interaction_supplement_prep (GcrImportInteraction *interaction,
-                                        GckAttributes *attributes)
+                                        GckBuilder *builder)
 {
 	GcrImportInteractionIface *iface;
 
 	g_return_if_fail (GCR_IS_IMPORT_INTERACTION (interaction));
-	g_return_if_fail (attributes != NULL);
+	g_return_if_fail (builder != NULL);
 
 	iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction);
 	if (iface->supplement != NULL)
-		(iface->supplement_prep) (interaction, attributes);
+		(iface->supplement_prep) (interaction, builder);
 }
 
 /**
  * gcr_import_interaction_supplement:
  * @interaction: the interaction
- * @attributes: supplemented attributes
+ * @builder: supplemented attributes
  * @cancellable: optional cancellable object
  * @error: location to store error on failure
  *
@@ -123,28 +123,28 @@ gcr_import_interaction_supplement_prep (GcrImportInteraction *interaction,
  */
 GTlsInteractionResult
 gcr_import_interaction_supplement (GcrImportInteraction *interaction,
-                                   GckAttributes *attributes,
+                                   GckBuilder *builder,
                                    GCancellable *cancellable,
                                    GError **error)
 {
 	GcrImportInteractionIface *iface;
 
 	g_return_val_if_fail (GCR_IS_IMPORT_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
-	g_return_val_if_fail (attributes != NULL, G_TLS_INTERACTION_UNHANDLED);
+	g_return_val_if_fail (builder != NULL, G_TLS_INTERACTION_UNHANDLED);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
 	g_return_val_if_fail (error == NULL || *error == NULL, G_TLS_INTERACTION_UNHANDLED);
 
 	iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction);
 	g_return_val_if_fail (iface->supplement != NULL, G_TLS_INTERACTION_UNHANDLED);
 
-	return (iface->supplement) (interaction, attributes, cancellable, error);
+	return (iface->supplement) (interaction, builder, cancellable, error);
 }
 
 
 /**
  * gcr_import_interaction_supplement_async:
  * @interaction: the interaction
- * @attributes: supplemented attributes
+ * @builder: supplemented attributes
  * @cancellable: optional cancellable object
  * @callback: called when the operation completes
  * @user_data: data to be passed to the callback
@@ -157,7 +157,7 @@ gcr_import_interaction_supplement (GcrImportInteraction *interaction,
  */
 void
 gcr_import_interaction_supplement_async (GcrImportInteraction *interaction,
-                                         GckAttributes *attributes,
+                                         GckBuilder *builder,
                                          GCancellable *cancellable,
                                          GAsyncReadyCallback callback,
                                          gpointer user_data)
@@ -165,13 +165,13 @@ gcr_import_interaction_supplement_async (GcrImportInteraction *interaction,
 	GcrImportInteractionIface *iface;
 
 	g_return_if_fail (GCR_IS_IMPORT_INTERACTION (interaction));
-	g_return_if_fail (attributes != NULL);
+	g_return_if_fail (builder != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
 	iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction);
 	g_return_if_fail (iface->supplement != NULL);
 
-	(iface->supplement_async) (interaction, attributes, cancellable, callback, user_data);
+	(iface->supplement_async) (interaction, builder, cancellable, callback, user_data);
 }
 
 /**
diff --git a/gcr/gcr-import-interaction.h b/gcr/gcr-import-interaction.h
index 2793d13..4ab95a2 100644
--- a/gcr/gcr-import-interaction.h
+++ b/gcr/gcr-import-interaction.h
@@ -48,15 +48,15 @@ struct _GcrImportInteractionIface {
 	GTypeInterface parent;
 
 	void                    (*supplement_prep)   (GcrImportInteraction *interaction,
-	                                              GckAttributes *attributes);
+	                                              GckBuilder *builder);
 
 	GTlsInteractionResult   (*supplement)        (GcrImportInteraction *interaction,
-	                                              GckAttributes *attributes,
+	                                              GckBuilder *builder,
 	                                              GCancellable *cancellable,
 	                                              GError **error);
 
 	void                    (*supplement_async)  (GcrImportInteraction *interaction,
-	                                              GckAttributes *attributes,
+	                                              GckBuilder *builder,
 	                                              GCancellable *cancellable,
 	                                              GAsyncReadyCallback callback,
 	                                              gpointer user_data);
@@ -72,15 +72,15 @@ struct _GcrImportInteractionIface {
 GType                  gcr_import_interaction_get_type             (void);
 
 void                   gcr_import_interaction_supplement_prep      (GcrImportInteraction *interaction,
-                                                                    GckAttributes *attributes);
+                                                                    GckBuilder *builder);
 
 GTlsInteractionResult  gcr_import_interaction_supplement           (GcrImportInteraction *interaction,
-                                                                    GckAttributes *attributes,
+                                                                    GckBuilder *builder,
                                                                     GCancellable *cancellable,
                                                                     GError **error);
 
 void                   gcr_import_interaction_supplement_async     (GcrImportInteraction *interaction,
-                                                                    GckAttributes *attributes,
+                                                                    GckBuilder *builder,
                                                                     GCancellable *cancellable,
                                                                     GAsyncReadyCallback callback,
                                                                     gpointer user_data);
diff --git a/gcr/gcr-importer.c b/gcr/gcr-importer.c
index cb35c5c..9ddaa64 100644
--- a/gcr/gcr-importer.c
+++ b/gcr/gcr-importer.c
@@ -218,7 +218,7 @@ gcr_importer_create_for_parsed (GcrParsed *parsed)
 	if (attrs != NULL)
 		gck_attributes_ref (attrs);
 	else
-		attrs = gck_attributes_new ();
+		attrs = gck_attributes_new_empty ();
 
 	seen = g_hash_table_new (g_direct_hash, g_direct_equal);
 
diff --git a/gcr/gcr-key-renderer.c b/gcr/gcr-key-renderer.c
index 9102069..82089b3 100644
--- a/gcr/gcr-key-renderer.c
+++ b/gcr/gcr-key-renderer.c
@@ -85,7 +85,7 @@ calculate_label (GcrKeyRenderer *self)
 static gint
 calculate_rsa_key_size (GckAttributes *attrs)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	gulong bits;
 
 	attr = gck_attributes_find (attrs, CKA_MODULUS);
@@ -103,7 +103,7 @@ calculate_rsa_key_size (GckAttributes *attrs)
 static guint
 calculate_dsa_key_size (GckAttributes *attrs)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	gulong bits;
 
 	attr = gck_attributes_find (attrs, CKA_PRIME);
@@ -212,6 +212,7 @@ static void
 gcr_key_renderer_class_init (GcrKeyRendererClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *registered;
 
 	gcr_key_renderer_parent_class = g_type_class_peek_parent (klass);
@@ -226,8 +227,8 @@ gcr_key_renderer_class_init (GcrKeyRendererClass *klass)
 	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
 
 	/* Register this as a view which can be loaded */
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	registered = gck_builder_end (&builder);
 	gcr_renderer_register (GCR_TYPE_KEY_RENDERER, registered);
 	gck_attributes_unref (registered);
 }
diff --git a/gcr/gcr-openssh.c b/gcr/gcr-openssh.c
index 0055078..c3970ab 100644
--- a/gcr/gcr-openssh.c
+++ b/gcr/gcr-openssh.c
@@ -124,7 +124,7 @@ keytype_to_algo (const gchar *algo,
 static gboolean
 read_decimal_mpi (const gchar *decimal,
                   gsize n_decimal,
-                  GckAttributes *attrs,
+                  GckBuilder *builder,
                   gulong attribute_type)
 {
 	gpointer data;
@@ -134,7 +134,7 @@ read_decimal_mpi (const gchar *decimal,
 	if (data == NULL)
 		return FALSE;
 
-	gck_attributes_add_data (attrs, attribute_type, data, n_data);
+	gck_builder_add_data (builder, attribute_type, data, n_data);
 	g_free (data);
 	return TRUE;
 }
@@ -161,6 +161,7 @@ parse_v1_public_line (const gchar *line,
 {
 	const gchar *word_bits, *word_exponent, *word_modulus, *word_options, *outer;
 	gsize len_bits, len_exponent, len_modulus, len_options, n_outer;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
 	gchar *label, *options;
 	EggBytes *bytes;
@@ -206,27 +207,27 @@ parse_v1_public_line (const gchar *line,
 	if (bits <= 0)
 		return GCR_ERROR_UNRECOGNIZED;
 
-	attrs = gck_attributes_new ();
-
-	if (!read_decimal_mpi (word_exponent, len_exponent, attrs, CKA_PUBLIC_EXPONENT) ||
-	    !read_decimal_mpi (word_modulus, len_modulus, attrs, CKA_MODULUS)) {
-		gck_attributes_unref (attrs);
+	if (!read_decimal_mpi (word_exponent, len_exponent, &builder, CKA_PUBLIC_EXPONENT) ||
+	    !read_decimal_mpi (word_modulus, len_modulus, &builder, CKA_MODULUS)) {
+		gck_builder_clear (&builder);
 		return GCR_ERROR_UNRECOGNIZED;
 	}
 
-	gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_ulong (&builder, CKA_KEY_TYPE, CKK_RSA);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
 
 	skip_spaces (&line, &length);
 	if (length > 0) {
 		label = g_strndup (line, length);
 		g_strstrip (label);
-		gck_attributes_add_string (attrs, CKA_LABEL, label);
+		gck_builder_add_string (&builder, CKA_LABEL, label);
 	}
 
 	if (word_options)
 		options = g_strndup (word_options, len_options);
 
+	attrs = gck_builder_end (&builder);
+
 	if (callback != NULL) {
 		bytes = egg_bytes_new_with_free_func (outer, n_outer,
 		                                      egg_bytes_unref,
@@ -244,7 +245,7 @@ parse_v1_public_line (const gchar *line,
 static gboolean
 read_buffer_mpi (EggBuffer *buffer,
                  gsize *offset,
-                 GckAttributes *attrs,
+                 GckBuilder *builder,
                  gulong attribute_type)
 {
 	const guchar *data;
@@ -253,59 +254,52 @@ read_buffer_mpi (EggBuffer *buffer,
 	if (!egg_buffer_get_byte_array (buffer, *offset, offset, &data, &len))
 		return FALSE;
 
-	gck_attributes_add_data (attrs, attribute_type, data, len);
+	gck_builder_add_data (builder, attribute_type, data, len);
 	return TRUE;
 }
 
-static GckAttributes *
+static gboolean
 read_v2_public_dsa (EggBuffer *buffer,
-                    gsize *offset)
+                    gsize *offset,
+                    GckBuilder *builder)
 {
-	GckAttributes *attrs;
-
-	attrs = gck_attributes_new ();
-
-	if (!read_buffer_mpi (buffer, offset, attrs, CKA_PRIME) ||
-	    !read_buffer_mpi (buffer, offset, attrs, CKA_SUBPRIME) ||
-	    !read_buffer_mpi (buffer, offset, attrs, CKA_BASE) ||
-	    !read_buffer_mpi (buffer, offset, attrs, CKA_VALUE)) {
-		gck_attributes_unref (attrs);
-		return NULL;
+	if (!read_buffer_mpi (buffer, offset, builder, CKA_PRIME) ||
+	    !read_buffer_mpi (buffer, offset, builder, CKA_SUBPRIME) ||
+	    !read_buffer_mpi (buffer, offset, builder, CKA_BASE) ||
+	    !read_buffer_mpi (buffer, offset, builder, CKA_VALUE)) {
+		return FALSE;
 	}
 
-	gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_DSA);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_ulong (builder, CKA_KEY_TYPE, CKK_DSA);
+	gck_builder_add_ulong (builder, CKA_CLASS, CKO_PUBLIC_KEY);
 
-	return attrs;
+	return TRUE;
 }
 
-static GckAttributes *
+static gboolean
 read_v2_public_rsa (EggBuffer *buffer,
-                    gsize *offset)
+                    gsize *offset,
+                    GckBuilder *builder)
 {
-	GckAttributes *attrs;
-
-	attrs = gck_attributes_new ();
-
-	if (!read_buffer_mpi (buffer, offset, attrs, CKA_PUBLIC_EXPONENT) ||
-	    !read_buffer_mpi (buffer, offset, attrs, CKA_MODULUS)) {
-		gck_attributes_unref (attrs);
-		return NULL;
+	if (!read_buffer_mpi (buffer, offset, builder, CKA_PUBLIC_EXPONENT) ||
+	    !read_buffer_mpi (buffer, offset, builder, CKA_MODULUS)) {
+		return FALSE;
 	}
 
-	gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_ulong (builder, CKA_KEY_TYPE, CKK_RSA);
+	gck_builder_add_ulong (builder, CKA_CLASS, CKO_PUBLIC_KEY);
 
-	return attrs;
+	return TRUE;
 }
 
-static GckAttributes *
+static gboolean
 read_v2_public_key (gulong algo,
                     gconstpointer data,
-                    gsize n_data)
+                    gsize n_data,
+                    GckBuilder *builder)
 {
-	GckAttributes *attrs;
 	EggBuffer buffer;
+	gboolean ret;
 	gsize offset;
 	gchar *stype;
 	int alg;
@@ -316,7 +310,7 @@ read_v2_public_key (gulong algo,
 	/* The string algorithm */
 	if (!egg_buffer_get_string (&buffer, offset, &offset,
 	                            &stype, (EggBufferAllocator)g_realloc))
-		return NULL;
+		return FALSE;
 
 	alg = keytype_to_algo (stype, stype ? strlen (stype) : 0);
 	g_free (stype);
@@ -324,15 +318,15 @@ read_v2_public_key (gulong algo,
 	if (alg != algo) {
 		g_message ("invalid or mis-matched algorithm in ssh public key: %s", stype);
 		egg_buffer_uninit (&buffer);
-		return NULL;
+		return FALSE;
 	}
 
 	switch (algo) {
 	case CKK_RSA:
-		attrs = read_v2_public_rsa (&buffer, &offset);
+		ret = read_v2_public_rsa (&buffer, &offset, builder);
 		break;
 	case CKK_DSA:
-		attrs = read_v2_public_dsa (&buffer, &offset);
+		ret = read_v2_public_dsa (&buffer, &offset, builder);
 		break;
 	default:
 		g_assert_not_reached ();
@@ -340,17 +334,18 @@ read_v2_public_key (gulong algo,
 	}
 
 	egg_buffer_uninit (&buffer);
-	return attrs;
+	return ret;
 }
 
-static GckAttributes *
+static gboolean
 decode_v2_public_key (gulong algo,
                       const gchar *data,
-                      gsize n_data)
+                      gsize n_data,
+                      GckBuilder *builder)
 {
-	GckAttributes *attrs;
 	gpointer decoded;
 	gsize n_decoded;
+	gboolean ret;
 	guint save;
 	gint state;
 
@@ -361,15 +356,15 @@ decode_v2_public_key (gulong algo,
 
 	if (!n_decoded) {
 		g_free (decoded);
-		return NULL;
+		return FALSE;
 	}
 
 	/* Parse the actual key */
-	attrs = read_v2_public_key (algo, decoded, n_decoded);
+	ret = read_v2_public_key (algo, decoded, n_decoded, builder);
 
 	g_free (decoded);
 
-	return attrs;
+	return ret;
 }
 
 static GcrDataError
@@ -381,6 +376,7 @@ parse_v2_public_line (const gchar *line,
 {
 	const gchar *word_options, *word_algo, *word_key;
 	gsize len_options, len_algo, len_key;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
 	gchar *options;
 	gchar *label = NULL;
@@ -428,9 +424,10 @@ parse_v2_public_line (const gchar *line,
 	if (!next_word (&line, &length, &word_key, &len_key))
 		return GCR_ERROR_FAILURE;
 
-	attrs = decode_v2_public_key (algo, word_key, len_key);
-	if (attrs == NULL)
+	if (!decode_v2_public_key (algo, word_key, len_key, &builder)) {
+		gck_builder_clear (&builder);
 		return GCR_ERROR_FAILURE;
+	}
 
 	if (word_options)
 		options = g_strndup (word_options, len_options);
@@ -442,9 +439,11 @@ parse_v2_public_line (const gchar *line,
 	if (length > 0) {
 		label = g_strndup (line, length);
 		g_strstrip (label);
-		gck_attributes_add_string (attrs, CKA_LABEL, label);
+		gck_builder_add_string (&builder, CKA_LABEL, label);
 	}
 
+	attrs = gck_builder_end (&builder);
+
 	if (callback != NULL) {
 		bytes = egg_bytes_new_with_free_func (outer, n_outer,
 		                                      egg_bytes_unref,
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index fdb73d4..1022e41 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -120,6 +120,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 struct _GcrParsed {
 	gint refs;
+	GckBuilder builder;
 	GckAttributes *attrs;
 	const gchar *description;
 	gchar *label;
@@ -221,8 +222,7 @@ parsed_attribute (GcrParsed *parsed,
                   gsize n_data)
 {
 	g_assert (parsed != NULL);
-	g_assert (parsed->attrs != NULL);
-	gck_attributes_add_data (parsed->attrs, type, data, n_data);
+	gck_builder_add_data (&parsed->builder, type, data, n_data);
 }
 
 static void
@@ -231,10 +231,9 @@ parsed_attribute_bytes (GcrParsed *parsed,
                         EggBytes *data)
 {
 	g_assert (parsed != NULL);
-	g_assert (parsed->attrs != NULL);
-	gck_attributes_add_data (parsed->attrs, type,
-	                         egg_bytes_get_data (data),
-	                         egg_bytes_get_size (data));
+	gck_builder_add_data (&parsed->builder, type,
+	                      egg_bytes_get_data (data),
+	                      egg_bytes_get_size (data));
 }
 
 static gboolean
@@ -283,8 +282,7 @@ parsed_ulong_attribute (GcrParsed *parsed,
                         gulong value)
 {
 	g_assert (parsed != NULL);
-	g_assert (parsed->attrs != NULL);
-	gck_attributes_add_ulong (parsed->attrs, type, value);
+	gck_builder_add_ulong (&parsed->builder, type, value);
 }
 
 static void
@@ -293,8 +291,7 @@ parsed_boolean_attribute (GcrParsed *parsed,
                           gboolean value)
 {
 	g_assert (parsed != NULL);
-	g_assert (parsed->attrs != NULL);
-	gck_attributes_add_boolean (parsed->attrs, type, value);
+	gck_builder_add_boolean (&parsed->builder, type, value);
 }
 
 
@@ -344,13 +341,13 @@ parsing_object (GcrParsed *parsed,
                 CK_OBJECT_CLASS klass)
 {
 	g_assert (parsed != NULL);
-	g_assert (parsed->attrs == NULL);
 
+	gck_builder_clear (&parsed->builder);
 	if (parsed->sensitive)
-		parsed->attrs = gck_attributes_new_full ((GckAllocator)egg_secure_realloc);
+		gck_builder_init_full (&parsed->builder, GCK_BUILDER_SECURE_MEMORY);
 	else
-		parsed->attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (parsed->attrs, CKA_CLASS, klass);
+		gck_builder_init_full (&parsed->builder, GCK_BUILDER_NONE);
+	gck_builder_add_ulong (&parsed->builder, CKA_CLASS, klass);
 	parsed_description (parsed, klass);
 }
 
@@ -362,11 +359,10 @@ parsed_attributes (GcrParsed *parsed,
 
 	g_assert (parsed != NULL);
 	g_assert (attrs != NULL);
-	g_assert (parsed->attrs == NULL);
 
-	parsed->attrs = gck_attributes_ref (attrs);
 	if (gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
 		parsed_description (parsed, klass);
+	gck_builder_add_all (&parsed->builder, attrs);
 }
 
 static void
@@ -398,6 +394,7 @@ pop_parsed (GcrParser *self,
 
 	self->pv->parsed = parsed->next;
 
+	gck_builder_clear (&parsed->builder);
 	gck_attributes_unref (parsed->attrs);
 	if (parsed->data)
 		egg_bytes_unref (parsed->data);
@@ -458,6 +455,9 @@ parsed_fire (GcrParser *self,
 	g_assert (GCR_IS_PARSER (self));
 	g_assert (parsed != NULL);
 	g_assert (parsed == self->pv->parsed);
+	g_assert (parsed->attrs == NULL);
+
+	parsed->attrs = gck_builder_end (&parsed->builder);
 
 	g_object_notify (G_OBJECT (self), "parsed-description");
 	g_object_notify (G_OBJECT (self), "parsed-attributes");
@@ -2672,6 +2672,7 @@ gcr_parsed_unref (gpointer parsed)
 	g_return_if_fail (parsed != NULL);
 
 	if (g_atomic_int_dec_and_test (&par->refs)) {
+		gck_builder_clear (&par->builder);
 		if (par->attrs)
 			gck_attributes_unref (par->attrs);
 		g_free (par->label);
diff --git a/gcr/gcr-pkcs11-certificate.c b/gcr/gcr-pkcs11-certificate.c
index 65462eb..ced8135 100644
--- a/gcr/gcr-pkcs11-certificate.c
+++ b/gcr/gcr-pkcs11-certificate.c
@@ -92,19 +92,18 @@ lookup_issuer_free (gpointer data)
 static GckAttributes *
 prepare_lookup_certificate_issuer (GcrCertificate *cert)
 {
-	GckAttributes *search;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	gpointer data;
 	gsize n_data;
 
-	search = gck_attributes_new ();
-	gck_attributes_add_ulong (search, CKA_CLASS, CKO_CERTIFICATE);
-	gck_attributes_add_ulong (search, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
 
 	data = gcr_certificate_get_issuer_raw (cert, &n_data);
-	gck_attributes_add_data (search, CKA_SUBJECT, data, n_data);
+	gck_builder_add_data (&builder, CKA_SUBJECT, data, n_data);
 	g_free (data);
 
-	return search;
+	return gck_builder_end (&builder);
 }
 
 static GcrCertificate*
@@ -193,7 +192,7 @@ gcr_pkcs11_certificate_constructor (GType type, guint n_props, GObjectConstructP
 {
 	gpointer obj = G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->constructor (type, n_props, props);
 	GckAttributes *attrs;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	gulong value;
 
 	attrs = gcr_pkcs11_certificate_get_attributes (obj);
@@ -302,7 +301,7 @@ gcr_pkcs11_certificate_get_der_data (GcrCertificate *cert,
                                      gsize *n_data)
 {
 	GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (cert);
-	GckAttribute *attr;
+	const GckAttribute *attr;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (n_data, NULL);
diff --git a/gcr/gcr-pkcs11-import-dialog.c b/gcr/gcr-pkcs11-import-dialog.c
index cd71482..7b801de 100644
--- a/gcr/gcr-pkcs11-import-dialog.c
+++ b/gcr/gcr-pkcs11-import-dialog.c
@@ -159,28 +159,28 @@ _gcr_pkcs11_import_dialog_new (GtkWindow *parent)
 
 void
 _gcr_pkcs11_import_dialog_get_supplements (GcrPkcs11ImportDialog *self,
-                                           GckAttributes *attributes)
+                                           GckBuilder *builder)
 {
 	const gchar *label;
 
 	g_return_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self));
-	g_return_if_fail (attributes != NULL);
+	g_return_if_fail (builder != NULL);
 
 	label = gtk_entry_get_text (self->label_entry);
 	if (self->label_changed && label != NULL && label[0])
-		gck_attributes_set_string (attributes, CKA_LABEL, label);
+		gck_builder_set_string (builder, CKA_LABEL, label);
 }
 
 void
 _gcr_pkcs11_import_dialog_set_supplements (GcrPkcs11ImportDialog *self,
-                                           GckAttributes *attributes)
+                                           GckBuilder *builder)
 {
 	gchar *label;
 
 	g_return_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self));
-	g_return_if_fail (attributes != NULL);
+	g_return_if_fail (builder != NULL);
 
-	if (!gck_attributes_find_string (attributes, CKA_LABEL, &label))
+	if (!gck_builder_find_string (builder, CKA_LABEL, &label))
 		label = NULL;
 
 	if (label == NULL)
diff --git a/gcr/gcr-pkcs11-import-dialog.h b/gcr/gcr-pkcs11-import-dialog.h
index 5c7da89..f970c7c 100644
--- a/gcr/gcr-pkcs11-import-dialog.h
+++ b/gcr/gcr-pkcs11-import-dialog.h
@@ -42,10 +42,10 @@ GType                   _gcr_pkcs11_import_dialog_get_type          (void) G_GNU
 GcrPkcs11ImportDialog * _gcr_pkcs11_import_dialog_new               (GtkWindow *parent);
 
 void                    _gcr_pkcs11_import_dialog_get_supplements   (GcrPkcs11ImportDialog *self,
-                                                                     GckAttributes *attributes);
+                                                                     GckBuilder *builder);
 
 void                    _gcr_pkcs11_import_dialog_set_supplements   (GcrPkcs11ImportDialog *self,
-                                                                     GckAttributes *attributes);
+                                                                     GckBuilder *builder);
 
 gboolean                _gcr_pkcs11_import_dialog_run               (GcrPkcs11ImportDialog *self);
 
diff --git a/gcr/gcr-pkcs11-import-interaction.c b/gcr/gcr-pkcs11-import-interaction.c
index e9a1833..2d42d7b 100644
--- a/gcr/gcr-pkcs11-import-interaction.c
+++ b/gcr/gcr-pkcs11-import-interaction.c
@@ -123,17 +123,17 @@ _gcr_pkcs11_import_interaction_ask_password (GTlsInteraction *interaction,
 
 static void
 _gcr_pkcs11_import_interaction_supplement_prep (GcrImportInteraction *interaction,
-                                                GckAttributes *attributes)
+                                                GckBuilder *builder)
 {
 	GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (interaction);
 
 	self->supplemented = FALSE;
-	_gcr_pkcs11_import_dialog_set_supplements (self->dialog, attributes);
+	_gcr_pkcs11_import_dialog_set_supplements (self->dialog, builder);
 }
 
 static GTlsInteractionResult
 _gcr_pkcs11_import_interaction_supplement (GcrImportInteraction *interaction,
-                                           GckAttributes *attributes,
+                                           GckBuilder *builder,
                                            GCancellable *cancellable,
                                            GError **error)
 {
@@ -146,7 +146,7 @@ _gcr_pkcs11_import_interaction_supplement (GcrImportInteraction *interaction,
 
 	self->supplemented = TRUE;
 	if (_gcr_pkcs11_import_dialog_run (self->dialog)) {
-		_gcr_pkcs11_import_dialog_get_supplements (self->dialog, attributes);
+		_gcr_pkcs11_import_dialog_get_supplements (self->dialog, builder);
 		return G_TLS_INTERACTION_HANDLED;
 
 	} else {
@@ -161,10 +161,10 @@ on_dialog_run_async (GObject *source,
                      gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	GckAttributes *attributes = g_simple_async_result_get_op_res_gpointer (res);
+	GckBuilder *builder = g_simple_async_result_get_op_res_gpointer (res);
 
 	if (_gcr_pkcs11_import_dialog_run_finish (GCR_PKCS11_IMPORT_DIALOG (source), result)) {
-		_gcr_pkcs11_import_dialog_get_supplements (GCR_PKCS11_IMPORT_DIALOG  (source), attributes);
+		_gcr_pkcs11_import_dialog_get_supplements (GCR_PKCS11_IMPORT_DIALOG  (source), builder);
 
 	} else {
 		g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_CANCELLED,
@@ -177,7 +177,7 @@ on_dialog_run_async (GObject *source,
 
 static void
 _gcr_pkcs11_import_interaction_supplement_async (GcrImportInteraction *interaction,
-                                                 GckAttributes *attributes,
+                                                 GckBuilder *builder,
                                                  GCancellable *cancellable,
                                                  GAsyncReadyCallback callback,
                                                  gpointer user_data)
@@ -196,8 +196,8 @@ _gcr_pkcs11_import_interaction_supplement_async (GcrImportInteraction *interacti
 
 	} else {
 		self->supplemented = TRUE;
-		g_simple_async_result_set_op_res_gpointer (res, gck_attributes_ref (attributes),
-		                                           (GDestroyNotify)gck_attributes_unref);
+		g_simple_async_result_set_op_res_gpointer (res, gck_builder_ref (builder),
+		                                           (GDestroyNotify)gck_builder_unref);
 		_gcr_pkcs11_import_dialog_run_async (self->dialog, cancellable,
 		                                     on_dialog_run_async, g_object_ref (res));
 	}
diff --git a/gcr/gcr-pkcs11-importer.c b/gcr/gcr-pkcs11-importer.c
index c60a17c..e46ed2d 100644
--- a/gcr/gcr-pkcs11-importer.c
+++ b/gcr/gcr-pkcs11-importer.c
@@ -74,7 +74,7 @@ typedef struct  {
 	GCancellable *cancellable;
 	gboolean prompted;
 	gboolean async;
-	GckAttributes *supplement;
+	GckBuilder *supplement;
 } GcrImporterData;
 
 /* State forward declarations */
@@ -231,21 +231,21 @@ typedef struct {
 } CertificateKeyPair;
 
 static void
-supplement_with_attributes (GckAttributes *attrs,
+supplement_with_attributes (GckBuilder *builder,
                             GckAttributes *supplements)
 {
-	GckAttribute *supplement;
+	const GckAttribute *supplement;
 	gint i;
 
 	for (i = 0; i < gck_attributes_count (supplements); i++) {
 		supplement = gck_attributes_at (supplements, i);
 		if (!gck_attribute_is_invalid (supplement) && supplement->length != 0)
-			gck_attributes_add (attrs, supplement);
+			gck_builder_add_owned (builder, supplement);
 	}
 }
 
 static void
-supplement_id_for_data (GckAttributes *attrs,
+supplement_id_for_data (GckBuilder *builder,
                         guchar *nonce,
                         gsize n_once,
                         gpointer data,
@@ -254,7 +254,7 @@ supplement_id_for_data (GckAttributes *attrs,
 	gcry_md_hd_t mdh;
 	gcry_error_t gcry;
 
-	if (gck_attributes_find (attrs, CKA_ID) != NULL)
+	if (gck_builder_find (builder, CKA_ID) != NULL)
 		return;
 
 	gcry = gcry_md_open (&mdh, GCRY_MD_SHA1, 0);
@@ -263,9 +263,9 @@ supplement_id_for_data (GckAttributes *attrs,
 	gcry_md_write (mdh, nonce, n_once);
 	gcry_md_write (mdh, data, n_data);
 
-	gck_attributes_add_data (attrs, CKA_ID,
-	                         gcry_md_read (mdh, 0),
-	                         gcry_md_get_algo_dlen (GCRY_MD_SHA1));
+	gck_builder_add_data (builder, CKA_ID,
+	                      gcry_md_read (mdh, 0),
+	                      gcry_md_get_algo_dlen (GCRY_MD_SHA1));
 
 	gcry_md_close (mdh);
 }
@@ -274,6 +274,7 @@ static void
 supplement_attributes (GcrPkcs11Importer *self,
                        GckAttributes *supplements)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GHashTable *pairs;
 	GHashTable *paired;
 	CertificateKeyPair *pair;
@@ -316,22 +317,32 @@ supplement_attributes (GcrPkcs11Importer *self,
 		}
 
 		fingerprint = NULL;
+		gck_builder_add_all (&builder, attrs);
+		gck_builder_set_boolean (&builder, CKA_TOKEN, CK_TRUE);
 
-		gck_attributes_set_boolean (attrs, CKA_TOKEN, CK_TRUE);
+		switch (klass) {
+		case CKO_CERTIFICATE:
+			gck_builder_set_boolean (&builder, CKA_PRIVATE, FALSE);
+			break;
+		case CKO_PRIVATE_KEY:
+			gck_builder_set_boolean (&builder, CKA_PRIVATE, TRUE);
+			gck_builder_add_boolean (&builder, CKA_DECRYPT, TRUE);
+			gck_builder_add_boolean (&builder, CKA_SIGN, TRUE);
+			gck_builder_add_boolean (&builder, CKA_SIGN_RECOVER, TRUE);
+			gck_builder_add_boolean (&builder, CKA_UNWRAP, TRUE);
+			gck_builder_add_boolean (&builder, CKA_SENSITIVE, TRUE);
+			break;
+		}
+
+		gck_attributes_unref (attrs);
+		l->data = attrs = gck_builder_end (&builder);
 
 		switch (klass) {
 		case CKO_CERTIFICATE:
-			gck_attributes_set_boolean (attrs, CKA_PRIVATE, FALSE);
 			if (pair != NULL && pair->certificate == NULL)
 				pair->certificate = attrs;
 			break;
 		case CKO_PRIVATE_KEY:
-			gck_attributes_set_boolean (attrs, CKA_PRIVATE, TRUE);
-			gck_attributes_add_boolean (attrs, CKA_DECRYPT, TRUE);
-			gck_attributes_add_boolean (attrs, CKA_SIGN, TRUE);
-			gck_attributes_add_boolean (attrs, CKA_SIGN_RECOVER, TRUE);
-			gck_attributes_add_boolean (attrs, CKA_UNWRAP, TRUE);
-			gck_attributes_add_boolean (attrs, CKA_SENSITIVE, TRUE);
 			if (pair != NULL && pair->private_key == NULL)
 				pair->private_key = attrs;
 			break;
@@ -354,16 +365,18 @@ supplement_attributes (GcrPkcs11Importer *self,
 			 * and do the same CKA_ID for both private key and certificate.
 			 */
 
-			supplement_with_attributes (pair->private_key, supplements);
-			supplement_id_for_data (pair->private_key, nonce, sizeof (nonce),
+			gck_builder_add_all (&builder, pair->private_key);
+			supplement_with_attributes (&builder, supplements);
+			supplement_id_for_data (&builder, nonce, sizeof (nonce),
 			                        fingerprint, strlen (fingerprint));
-			g_queue_push_tail (queue, pair->private_key);
+			g_queue_push_tail (queue, gck_builder_end (&builder));
 			g_hash_table_insert (paired, pair->private_key, "present");
 
-			supplement_with_attributes (pair->private_key, supplements);
-			supplement_id_for_data (pair->certificate, nonce, sizeof (nonce),
+			gck_builder_add_all (&builder, pair->certificate);
+			supplement_with_attributes (&builder, supplements);
+			supplement_id_for_data (&builder, nonce, sizeof (nonce),
 			                        fingerprint, strlen (fingerprint));
-			g_queue_push_tail (queue, pair->certificate);
+			g_queue_push_tail (queue, gck_builder_end (&builder));
 			g_hash_table_insert (paired, pair->certificate, "present");
 
 			/* Used the suplements for the pairs, don't use for unpaired stuff */
@@ -375,22 +388,24 @@ supplement_attributes (GcrPkcs11Importer *self,
 	for (l = self->queue->head; l != NULL; l = g_list_next (l)) {
 		attrs = l->data;
 		if (!g_hash_table_lookup (paired, attrs)) {
+			gck_builder_add_all (&builder, attrs);
 			if (!supplemented)
-				supplement_with_attributes (attrs, supplements);
+				supplement_with_attributes (&builder, supplements);
 
 			/*
 			 * Generate a CKA_ID based on the location of attrs in,
 			 * memory, since this together with the nonce should
 			 * be unique.
 			 */
-			supplement_id_for_data (attrs, nonce, sizeof (nonce),
+			supplement_id_for_data (&builder, nonce, sizeof (nonce),
 			                        &attrs, sizeof (gpointer));
 
-			g_queue_push_tail (queue, l->data);
+			g_queue_push_tail (queue, gck_builder_end (&builder));
 		}
 	}
 
 	/* And swap the new queue into place */
+	g_queue_foreach (self->queue, (GFunc)gck_attributes_unref, NULL);
 	g_queue_free (self->queue);
 	self->queue = queue;
 
@@ -403,9 +418,13 @@ complete_supplement (GSimpleAsyncResult *res,
                      GError *error)
 {
 	GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+	GckAttributes *attributes;
 
 	if (error == NULL) {
-		supplement_attributes (data->importer, data->supplement);
+		attributes = gck_builder_end (data->supplement);
+		supplement_attributes (data->importer, attributes);
+		gck_attributes_unref (attributes);
+
 		next_state (res, state_create_object);
 	} else {
 		g_simple_async_result_take_error (res, error);
@@ -457,14 +476,14 @@ supplement_prep (GSimpleAsyncResult *res)
 {
 	GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
 	GcrPkcs11Importer *self = data->importer;
-	GckAttribute *the_label = NULL;
-	GckAttribute *attr;
+	const GckAttribute *the_label = NULL;
+	const GckAttribute *attr;
 	gboolean first = TRUE;
 	GList *l;
 
 	if (data->supplement)
-		gck_attributes_unref (data->supplement);
-	data->supplement = gck_attributes_new ();
+		gck_builder_unref (data->supplement);
+	data->supplement = gck_builder_new (GCK_BUILDER_NONE);
 
 	/* Do we have a consistent label across all objects? */
 	for (l = self->queue->head; l != NULL; l = g_list_next (l)) {
@@ -478,9 +497,9 @@ supplement_prep (GSimpleAsyncResult *res)
 
 	/* If consistent label, set that in supplement data */
 	if (the_label != NULL)
-		gck_attributes_add (data->supplement, the_label);
+		gck_builder_add_data (data->supplement, CKA_LABEL, the_label->value, the_label->length);
 	else
-		gck_attributes_add_empty (data->supplement, CKA_LABEL);
+		gck_builder_add_empty (data->supplement, CKA_LABEL);
 
 	if (GCR_IS_IMPORT_INTERACTION (self->interaction))
 		gcr_import_interaction_supplement_prep (GCR_IMPORT_INTERACTION (self->interaction),
@@ -665,6 +684,7 @@ static void
 _gcr_pkcs11_importer_class_init (GcrPkcs11ImporterClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *registered;
 
 	gobject_class->dispose = _gcr_pkcs11_importer_dispose;
@@ -690,14 +710,14 @@ _gcr_pkcs11_importer_class_init (GcrPkcs11ImporterClass *klass)
 	           g_param_spec_pointer ("queued", "Queued", "Queued attributes",
 	                                 G_PARAM_READABLE));
 
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
-	gck_attributes_add_ulong (registered, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	registered = gck_builder_end (&builder);
 	gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, registered);
 	gck_attributes_unref (registered);
 
-	registered = gck_attributes_new ();
-	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+	registered = gck_builder_end (&builder);
 	gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, registered);
 	gck_attributes_unref (registered);
 
@@ -897,11 +917,18 @@ _gcr_pkcs11_importer_queue (GcrPkcs11Importer *self,
                             const gchar *label,
                             GckAttributes *attrs)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
+
 	g_return_if_fail (GCR_IS_PKCS11_IMPORTER (self));
 	g_return_if_fail (attrs != NULL);
 
-	if (label != NULL && !gck_attributes_find (attrs, CKA_LABEL))
-		gck_attributes_add_string (attrs, CKA_LABEL, label);
+	if (label != NULL && !gck_attributes_find (attrs, CKA_LABEL)) {
+		gck_builder_add_all (&builder, attrs);
+		gck_builder_add_string (&builder, CKA_LABEL, label);
+		attrs = gck_builder_end (&builder);
+	} else {
+		attrs = gck_attributes_ref (attrs);
+	}
 
-	g_queue_push_tail (self->queue, gck_attributes_ref (attrs));
+	g_queue_push_tail (self->queue, attrs);
 }
diff --git a/gcr/gcr-subject-public-key.c b/gcr/gcr-subject-public-key.c
index 6a50a08..dbef1af 100644
--- a/gcr/gcr-subject-public-key.c
+++ b/gcr/gcr-subject-public-key.c
@@ -37,21 +37,21 @@
 #include <gcrypt.h>
 
 static gboolean
-check_object_basics (GckAttributes *attributes,
+check_object_basics (GckBuilder *builder,
                      gulong *klass,
                      gulong *type)
 {
 	g_assert (klass != NULL);
 	g_assert (type != NULL);
 
-	if (!gck_attributes_find_ulong (attributes, CKA_CLASS, klass))
+	if (!gck_builder_find_ulong (builder, CKA_CLASS, klass))
 		return FALSE;
 
 	if (*klass == CKO_PUBLIC_KEY || *klass == CKO_PRIVATE_KEY)
-		return gck_attributes_find_ulong (attributes, CKA_KEY_TYPE, type);
+		return gck_builder_find_ulong (builder, CKA_KEY_TYPE, type);
 
 	else if (*klass == CKO_CERTIFICATE)
-		return gck_attributes_find_ulong (attributes, CKA_CERTIFICATE_TYPE, type);
+		return gck_builder_find_ulong (builder, CKA_CERTIFICATE_TYPE, type);
 
 	*type = GCK_INVALID;
 	return FALSE;
@@ -59,7 +59,7 @@ check_object_basics (GckAttributes *attributes,
 
 static gboolean
 load_object_basics (GckObject *object,
-                    GckAttributes *attributes,
+                    GckBuilder *builder,
                     GCancellable *cancellable,
                     gulong *klass,
                     gulong *type,
@@ -71,7 +71,7 @@ load_object_basics (GckObject *object,
 	g_assert (klass != NULL);
 	g_assert (type != NULL);
 
-	if (check_object_basics (attributes, klass, type)) {
+	if (check_object_basics (builder, klass, type)) {
 		_gcr_debug ("already loaded: class = %lu, type = %lu", *klass, *type);
 		return TRUE;
 	}
@@ -84,10 +84,10 @@ load_object_basics (GckObject *object,
 		return FALSE;
 	}
 
-	gck_attributes_set_all (attributes, attrs);
+	gck_builder_set_all (builder, attrs);
 	gck_attributes_unref (attrs);
 
-	if (!check_object_basics (attributes, klass, type))
+	if (!check_object_basics (builder, klass, type))
 		return FALSE;
 
 	_gcr_debug ("loaded: class = %lu, type = %lu", *klass, *type);
@@ -95,22 +95,22 @@ load_object_basics (GckObject *object,
 }
 
 static gboolean
-check_x509_attributes (GckAttributes *attributes)
+check_x509_attributes (GckBuilder *builder)
 {
-	GckAttribute *value = gck_attributes_find (attributes, CKA_VALUE);
+	const GckAttribute *value = gck_builder_find (builder, CKA_VALUE);
 	return (value && !gck_attribute_is_invalid (value));
 }
 
 static gboolean
 load_x509_attributes (GckObject *object,
-                      GckAttributes *attributes,
+                      GckBuilder *builder,
                       GCancellable *cancellable,
                       GError **lerror)
 {
 	GckAttributes *attrs;
 	GError *error = NULL;
 
-	if (check_x509_attributes (attributes)) {
+	if (check_x509_attributes (builder)) {
 		_gcr_debug ("already loaded");
 		return TRUE;
 	}
@@ -123,20 +123,20 @@ load_x509_attributes (GckObject *object,
 		return FALSE;
 	}
 
-	gck_attributes_set_all (attributes, attrs);
+	gck_builder_set_all (builder, attrs);
 	gck_attributes_unref (attrs);
 
-	return check_x509_attributes (attributes);
+	return check_x509_attributes (builder);
 }
 
 static gboolean
-check_rsa_attributes (GckAttributes *attributes)
+check_rsa_attributes (GckBuilder *builder)
 {
-	GckAttribute *modulus;
-	GckAttribute *exponent;
+	const GckAttribute *modulus;
+	const GckAttribute *exponent;
 
-	modulus = gck_attributes_find (attributes, CKA_MODULUS);
-	exponent = gck_attributes_find (attributes, CKA_PUBLIC_EXPONENT);
+	modulus = gck_builder_find (builder, CKA_MODULUS);
+	exponent = gck_builder_find (builder, CKA_PUBLIC_EXPONENT);
 
 	return (modulus && !gck_attribute_is_invalid (modulus) &&
 	        exponent && !gck_attribute_is_invalid (exponent));
@@ -144,14 +144,14 @@ check_rsa_attributes (GckAttributes *attributes)
 
 static gboolean
 load_rsa_attributes (GckObject *object,
-                     GckAttributes *attributes,
+                     GckBuilder *builder,
                      GCancellable *cancellable,
                      GError **lerror)
 {
 	GckAttributes *attrs;
 	GError *error = NULL;
 
-	if (check_rsa_attributes (attributes)) {
+	if (check_rsa_attributes (builder)) {
 		_gcr_debug ("rsa attributes already loaded");
 		return TRUE;
 	}
@@ -164,10 +164,10 @@ load_rsa_attributes (GckObject *object,
 		return FALSE;
 	}
 
-	gck_attributes_set_all (attributes, attrs);
+	gck_builder_set_all (builder, attrs);
 	gck_attributes_unref (attrs);
 
-	return check_rsa_attributes (attributes);
+	return check_rsa_attributes (builder);
 }
 
 static GckObject *
@@ -175,6 +175,7 @@ lookup_public_key (GckObject *object,
                    GCancellable *cancellable,
                    GError **lerror)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *match;
 	GError *error = NULL;
 	GckSession *session;
@@ -190,9 +191,9 @@ lookup_public_key (GckObject *object,
 		return NULL;
 	}
 
-	match = gck_attributes_new ();
-	gck_attributes_add_ulong (match, CKA_CLASS, CKO_PUBLIC_KEY);
-	gck_attributes_add_data (match, CKA_ID, id, n_id);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_add_data (&builder, CKA_ID, id, n_id);
+	match = gck_builder_end (&builder);
 	session = gck_object_get_session (object);
 	g_free (id);
 
@@ -217,17 +218,17 @@ lookup_public_key (GckObject *object,
 }
 
 static gboolean
-check_dsa_attributes (GckAttributes *attributes)
+check_dsa_attributes (GckBuilder *builder)
 {
-	GckAttribute *prime;
-	GckAttribute *subprime;
-	GckAttribute *base;
-	GckAttribute *value;
+	const GckAttribute *prime;
+	const GckAttribute *subprime;
+	const GckAttribute *base;
+	const GckAttribute *value;
 
-	prime = gck_attributes_find (attributes, CKA_PRIME);
-	subprime = gck_attributes_find (attributes, CKA_SUBPRIME);
-	base = gck_attributes_find (attributes, CKA_BASE);
-	value = gck_attributes_find (attributes, CKA_VALUE);
+	prime = gck_builder_find (builder, CKA_PRIME);
+	subprime = gck_builder_find (builder, CKA_SUBPRIME);
+	base = gck_builder_find (builder, CKA_BASE);
+	value = gck_builder_find (builder, CKA_VALUE);
 
 	return (prime && !gck_attribute_is_invalid (prime) &&
 	        subprime && !gck_attribute_is_invalid (subprime) &&
@@ -237,7 +238,7 @@ check_dsa_attributes (GckAttributes *attributes)
 
 static gboolean
 load_dsa_attributes (GckObject *object,
-                     GckAttributes *attributes,
+                     GckBuilder *builder,
                      GCancellable *cancellable,
                      GError **lerror)
 {
@@ -246,10 +247,10 @@ load_dsa_attributes (GckObject *object,
 	GckObject *publi;
 	gulong klass;
 
-	if (check_dsa_attributes (attributes))
+	if (check_dsa_attributes (builder))
 		return TRUE;
 
-	if (!gck_attributes_find_ulong (attributes, CKA_CLASS, &klass))
+	if (!gck_builder_find_ulong (builder, CKA_CLASS, &klass))
 		g_return_val_if_reached (FALSE);
 
 	/* If it's a private key, find the public one */
@@ -274,17 +275,17 @@ load_dsa_attributes (GckObject *object,
 	}
 
 	/* We've made sure to load info from the public key, so change class */
-	gck_attributes_set_ulong (attributes, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_builder_set_ulong (builder, CKA_CLASS, CKO_PUBLIC_KEY);
 
-	gck_attributes_set_all (attributes, loaded);
+	gck_builder_set_all (builder, loaded);
 	gck_attributes_unref (loaded);
 
-	return check_dsa_attributes (attributes);
+	return check_dsa_attributes (builder);
 }
 
 static gboolean
 load_attributes (GckObject *object,
-                 GckAttributes *attributes,
+                 GckBuilder *builder,
                  GCancellable *cancellable,
                  GError **lerror)
 {
@@ -292,7 +293,7 @@ load_attributes (GckObject *object,
 	gulong klass;
 	gulong type;
 
-	if (!load_object_basics (object, attributes, cancellable,
+	if (!load_object_basics (object, builder, cancellable,
 	                         &klass, &type, lerror))
 		return FALSE;
 
@@ -301,7 +302,7 @@ load_attributes (GckObject *object,
 	case CKO_CERTIFICATE:
 		switch (type) {
 		case CKC_X_509:
-			ret = load_x509_attributes (object, attributes, cancellable, lerror);
+			ret = load_x509_attributes (object, builder, cancellable, lerror);
 			break;
 		default:
 			_gcr_debug ("unsupported certificate type: %lu", type);
@@ -313,10 +314,10 @@ load_attributes (GckObject *object,
 	case CKO_PRIVATE_KEY:
 		switch (type) {
 		case CKK_RSA:
-			ret = load_rsa_attributes (object, attributes, cancellable, lerror);
+			ret = load_rsa_attributes (object, builder, cancellable, lerror);
 			break;
 		case CKK_DSA:
-			ret = load_dsa_attributes (object, attributes, cancellable, lerror);
+			ret = load_dsa_attributes (object, builder, cancellable, lerror);
 			break;
 		default:
 			_gcr_debug ("unsupported key type: %lu", type);
@@ -338,12 +339,12 @@ load_attributes (GckObject *object,
 }
 
 static gboolean
-check_attributes (GckAttributes *attributes)
+check_attributes (GckBuilder *builder)
 {
 	gulong klass;
 	gulong type;
 
-	if (!check_object_basics (attributes, &klass, &type))
+	if (!check_object_basics (builder, &klass, &type))
 		return FALSE;
 
 	switch (klass) {
@@ -351,7 +352,7 @@ check_attributes (GckAttributes *attributes)
 	case CKO_CERTIFICATE:
 		switch (type) {
 		case CKC_X_509:
-			return check_x509_attributes (attributes);
+			return check_x509_attributes (builder);
 		default:
 			return FALSE;
 		}
@@ -360,9 +361,9 @@ check_attributes (GckAttributes *attributes)
 	case CKO_PRIVATE_KEY:
 		switch (type) {
 		case CKK_RSA:
-			return check_rsa_attributes (attributes);
+			return check_rsa_attributes (builder);
 		case CKK_DSA:
-			return check_dsa_attributes (attributes);
+			return check_dsa_attributes (builder);
 		default:
 			return FALSE;
 		}
@@ -372,30 +373,20 @@ check_attributes (GckAttributes *attributes)
 	}
 }
 
-static GckAttributes *
-lookup_attributes (GckObject *object)
+static void
+lookup_attributes (GckObject *object,
+                   GckBuilder *builder)
 {
 	GckObjectAttributes *oakey;
+	GckAttributes *attrs;
 
 	if (GCK_IS_OBJECT_ATTRIBUTES (object)) {
 		oakey = GCK_OBJECT_ATTRIBUTES (object);
-		return gck_object_attributes_get_attributes (oakey);
-	}
-
-	return NULL;
-}
-
-static void
-attributes_replace_with_copy_or_new (GckAttributes **attributes)
-{
-	g_assert (attributes);
-
-	if (*attributes) {
-		GckAttributes *copy = gck_attributes_dup (*attributes);
-		gck_attributes_unref (*attributes);
-		*attributes = copy;
-	} else {
-		*attributes = gck_attributes_new ();
+		attrs = gck_object_attributes_get_attributes (oakey);
+		if (attrs != NULL) {
+			gck_builder_add_all (builder, attrs);
+			gck_attributes_unref (attrs);
+		}
 	}
 }
 
@@ -404,6 +395,7 @@ _gcr_subject_public_key_load (GckObject *key,
                               GCancellable *cancellable,
                               GError **error)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attributes;
 	GNode *asn;
 
@@ -411,17 +403,16 @@ _gcr_subject_public_key_load (GckObject *key,
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	attributes = lookup_attributes (key);
-
-	if (!attributes || !check_attributes (attributes)) {
-		attributes_replace_with_copy_or_new (&attributes);
+	lookup_attributes (key, &builder);
 
-		if (!load_attributes (key, attributes, cancellable, error)) {
-			gck_attributes_unref (attributes);
+	if (!check_attributes (&builder)) {
+		if (!load_attributes (key, &builder, cancellable, error)) {
+			gck_builder_clear (&builder);
 			return NULL;
 		}
 	}
 
+	attributes = gck_builder_end (&builder);
 	asn = _gcr_subject_public_key_for_attributes (attributes);
 	if (asn == NULL) {
 		g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
@@ -434,7 +425,7 @@ _gcr_subject_public_key_load (GckObject *key,
 
 typedef struct {
 	GckObject *object;
-	GckAttributes *attributes;
+	GckBuilder builder;
 } LoadClosure;
 
 static void
@@ -442,7 +433,7 @@ load_closure_free (gpointer data)
 {
 	LoadClosure *closure = data;
 	g_object_unref (closure->object);
-	gck_attributes_unref (closure->attributes);
+	gck_builder_clear (&closure->builder);
 	g_slice_free (LoadClosure, closure);
 }
 
@@ -454,7 +445,7 @@ thread_key_attributes (GSimpleAsyncResult *res,
 	LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
 	GError *error = NULL;
 
-	if (!load_attributes (closure->object, closure->attributes, cancellable, &error))
+	if (!load_attributes (closure->object, &closure->builder, cancellable, &error))
 		g_simple_async_result_take_error (res, error);
 }
 
@@ -475,16 +466,15 @@ _gcr_subject_public_key_load_async (GckObject *key,
 
 	closure = g_slice_new0 (LoadClosure);
 	closure->object = g_object_ref (key);
-	closure->attributes = lookup_attributes (key);
+	lookup_attributes (key, &closure->builder);
 	g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free);
 
-	if (closure->attributes && check_attributes (closure->attributes)) {
+	if (check_attributes (&closure->builder)) {
 		g_simple_async_result_complete_in_idle (res);
 		g_object_unref (res);
 		return;
 	}
 
-	attributes_replace_with_copy_or_new (&closure->attributes);
 	g_simple_async_result_run_in_thread (res, thread_key_attributes,
 	                                     G_PRIORITY_DEFAULT, cancellable);
 	g_object_unref (res);
@@ -494,6 +484,7 @@ GNode *
 _gcr_subject_public_key_load_finish (GAsyncResult *result,
                                      GError **error)
 {
+	GckAttributes *attributes;
 	GSimpleAsyncResult *res;
 	LoadClosure *closure;
 	GNode *asn;
@@ -507,12 +498,14 @@ _gcr_subject_public_key_load_finish (GAsyncResult *result,
 		return NULL;
 
 	closure = g_simple_async_result_get_op_res_gpointer (res);
-	asn = _gcr_subject_public_key_for_attributes (closure->attributes);
+	attributes = gck_builder_end (&closure->builder);
+	asn = _gcr_subject_public_key_for_attributes (attributes);
 	if (asn == NULL) {
 		g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
 		                     _("Couldn't build public key"));
 	}
 
+	gck_attributes_unref (attributes);
 	return asn;
 }
 
@@ -520,8 +513,8 @@ static gboolean
 rsa_subject_public_key_from_attributes (GckAttributes *attrs,
                                         GNode *info_asn)
 {
-	GckAttribute *modulus;
-	GckAttribute *exponent;
+	const GckAttribute *modulus;
+	const GckAttribute *exponent;
 	GNode *key_asn;
 	GNode *params_asn;
 	EggBytes *key;
@@ -574,10 +567,10 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs,
 
 static gboolean
 dsa_subject_public_key_from_private (GNode *key_asn,
-                                     GckAttribute *ap,
-                                     GckAttribute *aq,
-                                     GckAttribute *ag,
-                                     GckAttribute *ax)
+                                     const GckAttribute *ap,
+                                     const GckAttribute *aq,
+                                     const GckAttribute *ag,
+                                     const GckAttribute *ax)
 {
 	gcry_mpi_t mp, mq, mg, mx, my;
 	size_t n_buffer;
@@ -620,7 +613,7 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
                                         gulong klass,
                                         GNode *info_asn)
 {
-	GckAttribute *value, *g, *q, *p;
+	const GckAttribute *value, *g, *q, *p;
 	GNode *key_asn, *params_asn;
 	EggBytes *key;
 	EggBytes *params;
@@ -690,7 +683,7 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
 static GNode *
 cert_subject_public_key_from_attributes (GckAttributes *attributes)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	EggBytes *bytes;
 	GNode *cert;
 	GNode *asn;
diff --git a/gcr/gcr-trust.c b/gcr/gcr-trust.c
index b28b28c..34b86c5 100644
--- a/gcr/gcr-trust.c
+++ b/gcr/gcr-trust.c
@@ -114,22 +114,20 @@ trust_closure_free (gpointer data)
 	g_free (closure);
 }
 
-static GckAttributes*
-prepare_trust_attrs (GcrCertificate *certificate, CK_X_ASSERTION_TYPE type)
+static void
+prepare_trust_attrs (GcrCertificate *certificate,
+                     CK_X_ASSERTION_TYPE type,
+                     GckBuilder *builder)
 {
-	GckAttributes *attrs;
 	gconstpointer data;
 	gsize n_data;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION);
-	gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, type);
+	gck_builder_add_ulong (builder, CKA_CLASS, CKO_X_TRUST_ASSERTION);
+	gck_builder_add_ulong (builder, CKA_X_ASSERTION_TYPE, type);
 
 	data = gcr_certificate_get_der_data (certificate, &n_data);
-	g_return_val_if_fail (data, NULL);
-	gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, data, n_data);
-
-	return attrs;
+	g_return_if_fail (data);
+	gck_builder_add_data (builder, CKA_X_CERTIFICATE_VALUE, data, n_data);
 }
 
 /* ----------------------------------------------------------------------------------
@@ -139,15 +137,14 @@ prepare_trust_attrs (GcrCertificate *certificate, CK_X_ASSERTION_TYPE type)
 static GckAttributes *
 prepare_is_certificate_pinned (GcrCertificate *certificate, const gchar *purpose, const gchar *peer)
 {
-	GckAttributes *attrs;
+	GckBuilder builder = GCK_BUILDER_INIT;
 
-	attrs = prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE);
-	g_return_val_if_fail (attrs, NULL);
+	prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE, &builder);
 
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose);
-	gck_attributes_add_string (attrs, CKA_X_PEER, peer);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
+	gck_builder_add_string (&builder, CKA_X_PEER, peer);
 
-	return attrs;
+	return gck_builder_end (&builder);
 }
 
 static gboolean
@@ -311,16 +308,15 @@ gcr_trust_is_certificate_pinned_finish (GAsyncResult *result, GError **error)
 static GckAttributes *
 prepare_add_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer)
 {
-	GckAttributes *attrs;
+	GckBuilder builder = GCK_BUILDER_INIT;
 
-	attrs = prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE);
-	g_return_val_if_fail (attrs, NULL);
+	prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE, &builder);
 
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose);
-	gck_attributes_add_string (attrs, CKA_X_PEER, peer);
-	gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
+	gck_builder_add_string (&builder, CKA_X_PEER, peer);
+	gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
 
-	return attrs;
+	return gck_builder_end (&builder);
 }
 
 static gboolean
@@ -328,6 +324,7 @@ perform_add_pinned_certificate (GckAttributes *search,
                                 GCancellable *cancellable,
                                 GError **error)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attrs;
 	gboolean ret = FALSE;
 	GError *lerr = NULL;
@@ -360,8 +357,8 @@ perform_add_pinned_certificate (GckAttributes *search,
 		return TRUE;
 	}
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_all (attrs, search);
+	gck_builder_add_all (&builder, search);
+	attrs = gck_builder_end (&builder);
 
 	/* TODO: Add relevant label */
 
@@ -530,15 +527,13 @@ static GckAttributes *
 prepare_remove_pinned_certificate (GcrCertificate *certificate, const gchar *purpose,
                                    const gchar *peer)
 {
-	GckAttributes *attrs;
-
-	attrs = prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE);
-	g_return_val_if_fail (attrs, NULL);
+	GckBuilder builder = GCK_BUILDER_INIT;
 
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose);
-	gck_attributes_add_string (attrs, CKA_X_PEER, peer);
+	prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE, &builder);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
+	gck_builder_add_string (&builder, CKA_X_PEER, peer);
 
-	return attrs;
+	return gck_builder_end (&builder);
 }
 
 static gboolean
@@ -714,14 +709,12 @@ gcr_trust_remove_pinned_certificate_finish (GAsyncResult *result, GError **error
 static GckAttributes *
 prepare_is_certificate_anchored (GcrCertificate *certificate, const gchar *purpose)
 {
-	GckAttributes *attrs;
-
-	attrs = prepare_trust_attrs (certificate, CKT_X_ANCHORED_CERTIFICATE);
-	g_return_val_if_fail (attrs, NULL);
+	GckBuilder builder = GCK_BUILDER_INIT;
 
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose);
+	prepare_trust_attrs (certificate, CKT_X_ANCHORED_CERTIFICATE, &builder);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
 
-	return attrs;
+	return gck_builder_end (&builder);
 }
 
 static gboolean
diff --git a/gcr/gcr.symbols b/gcr/gcr.symbols
index 1482480..0475803 100644
--- a/gcr/gcr.symbols
+++ b/gcr/gcr.symbols
@@ -105,3 +105,4 @@ gcr_viewer_widget_load_data
 gcr_viewer_widget_load_file
 gcr_viewer_widget_new
 gcr_viewer_widget_show_error
+SECMEM_pool_data_v1_0
diff --git a/gcr/tests/frob-parser.c b/gcr/tests/frob-parser.c
index 2459a10..2ed392a 100644
--- a/gcr/tests/frob-parser.c
+++ b/gcr/tests/frob-parser.c
@@ -32,7 +32,7 @@
 static gboolean
 dump_certificate (GckAttributes *attrs, const gchar *filename)
 {
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	GcrCertificate *cert;
 	gchar *subject;
 	gulong klass;
diff --git a/gcr/tests/test-certificate-chain.c b/gcr/tests/test-certificate-chain.c
index a70c877..87488d0 100644
--- a/gcr/tests/test-certificate-chain.c
+++ b/gcr/tests/test-certificate-chain.c
@@ -178,7 +178,7 @@ setup (Test *test, gconstpointer unused)
 static void
 add_certificate_to_module (GcrCertificate *certificate)
 {
-	GckAttributes *attrs;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	gconstpointer data;
 	gsize n_data, n_subject;
 	gpointer subject;
@@ -190,12 +190,11 @@ add_certificate_to_module (GcrCertificate *certificate)
 	g_assert (subject);
 
 	/* Add a certificate to the module */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_VALUE, data, n_data);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
-	gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509);
-	gck_attributes_add_data (attrs, CKA_SUBJECT, subject, n_subject);
-	gck_mock_module_take_object (attrs);
+	gck_builder_add_data (&builder, CKA_VALUE, data, n_data);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	gck_builder_add_data (&builder, CKA_SUBJECT, subject, n_subject);
+	gck_mock_module_take_object (gck_builder_end (&builder));
 
 	g_free (subject);
 }
@@ -203,7 +202,7 @@ add_certificate_to_module (GcrCertificate *certificate)
 static void
 add_anchor_to_module (GcrCertificate *certificate, const gchar *purpose)
 {
-	GckAttributes *attrs;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	gconstpointer data;
 	gsize n_data;
 
@@ -211,18 +210,17 @@ add_anchor_to_module (GcrCertificate *certificate, const gchar *purpose)
 	g_assert (data);
 
 	/* And add a pinned certificate for the signed certificate */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, data, n_data);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION);
-	gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE);
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose);
-	gck_mock_module_take_object (attrs);
+	gck_builder_add_data (&builder, CKA_X_CERTIFICATE_VALUE, data, n_data);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_X_TRUST_ASSERTION);
+	gck_builder_add_ulong (&builder, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
+	gck_mock_module_take_object (gck_builder_end (&builder));
 }
 
 static void
 add_pinned_to_module (GcrCertificate *certificate, const gchar *purpose, const gchar *host)
 {
-	GckAttributes *attrs;
+	GckBuilder builder = GCK_BUILDER_INIT;
 	gconstpointer data;
 	gsize n_data;
 
@@ -230,13 +228,12 @@ add_pinned_to_module (GcrCertificate *certificate, const gchar *purpose, const g
 	g_assert (data);
 
 	/* And add a pinned certificate for the signed certificate */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, data, n_data);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION);
-	gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, CKT_X_PINNED_CERTIFICATE);
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose);
-	gck_attributes_add_string (attrs, CKA_X_PEER, host);
-	gck_mock_module_take_object (attrs);
+	gck_builder_add_data (&builder, CKA_X_CERTIFICATE_VALUE, data, n_data);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_X_TRUST_ASSERTION);
+	gck_builder_add_ulong (&builder, CKA_X_ASSERTION_TYPE, CKT_X_PINNED_CERTIFICATE);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, purpose);
+	gck_builder_add_string (&builder, CKA_X_PEER, host);
+	gck_mock_module_take_object (gck_builder_end (&builder));
 }
 
 static void
diff --git a/gcr/tests/test-fingerprint.c b/gcr/tests/test-fingerprint.c
index 8851514..fd90bb1 100644
--- a/gcr/tests/test-fingerprint.c
+++ b/gcr/tests/test-fingerprint.c
@@ -110,15 +110,14 @@ parse_attributes_for_key (EggBytes *data)
 static GckAttributes *
 build_attributes_for_cert (EggBytes *data)
 {
-	GckAttributes *attrs;
+	GckBuilder builder = GCK_BUILDER_INIT;
 
-	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_VALUE, egg_bytes_get_data (data),
-	                         egg_bytes_get_size (data));
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
-	gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	gck_builder_add_data (&builder, CKA_VALUE, egg_bytes_get_data (data),
+	                      egg_bytes_get_size (data));
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
 
-	return attrs;
+	return gck_builder_end (&builder);
 }
 
 static EggBytes *
diff --git a/gcr/tests/test-pkcs11-certificate.c b/gcr/tests/test-pkcs11-certificate.c
index d6fea90..29c1b29 100644
--- a/gcr/tests/test-pkcs11-certificate.c
+++ b/gcr/tests/test-pkcs11-certificate.c
@@ -49,8 +49,8 @@ typedef struct {
 static void
 setup (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GList *modules = NULL;
-	GckAttributes *attrs;
 	CK_FUNCTION_LIST_PTR f;
 	GckModule *module;
 	EggBytes *subject;
@@ -89,14 +89,13 @@ setup (Test *test, gconstpointer unused)
 	subject = egg_asn1x_get_element_raw (node);
 
 	/* Add a certificate to the module */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_data (attrs, CKA_VALUE, test->cert_data, test->n_cert_data);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
-	gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509);
-	gck_attributes_add_data (attrs, CKA_SUBJECT,
-	                         egg_bytes_get_data (subject),
-	                         egg_bytes_get_size (subject));
-	gck_mock_module_take_object (attrs);
+	gck_builder_add_data (&builder, CKA_VALUE, test->cert_data, test->n_cert_data);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	gck_builder_add_data (&builder, CKA_SUBJECT,
+	                      egg_bytes_get_data (subject),
+	                      egg_bytes_get_size (subject));
+	gck_mock_module_take_object (gck_builder_end (&builder));
 
 	egg_bytes_unref (bytes);
 	egg_bytes_unref (subject);
@@ -123,7 +122,7 @@ test_lookup_certificate_issuer (Test *test, gconstpointer unused)
 	GcrCertificate *cert, *issuer;
 	GError *error = NULL;
 	GckAttributes *attrs;
-	GckAttribute *attr;
+	const GckAttribute *attr;
 	gconstpointer der;
 	gsize n_der;
 
diff --git a/gcr/tests/test-subject-public-key.c b/gcr/tests/test-subject-public-key.c
index 0e99563..8397262 100644
--- a/gcr/tests/test-subject-public-key.c
+++ b/gcr/tests/test-subject-public-key.c
@@ -272,22 +272,26 @@ static void
 setup_loading (TestLoading *test,
                gconstpointer fixture)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	const gchar *id = "test-id";
 	gulong handle;
 
 	setup_attributes (&test->at, fixture);
 	setup_module (&test->mo, NULL);
 
-	gck_attributes_add_string (test->at.crt_attrs, CKA_ID, id);
-	handle = gck_mock_module_take_object (gck_attributes_ref (test->at.crt_attrs));
+	gck_builder_add_all (&builder, test->at.crt_attrs);
+	gck_builder_add_string (&builder, CKA_ID, id);
+	handle = gck_mock_module_take_object (gck_builder_end (&builder));
 	test->crt_object = gck_object_from_handle (test->mo.session, handle);
 
-	gck_attributes_add_string (test->at.pub_attrs, CKA_ID, id);
-	handle = gck_mock_module_take_object (gck_attributes_ref (test->at.pub_attrs));
+	gck_builder_add_all (&builder, test->at.pub_attrs);
+	gck_builder_add_string (&builder, CKA_ID, id);
+	handle = gck_mock_module_take_object (gck_builder_end (&builder));
 	test->pub_object = gck_object_from_handle (test->mo.session, handle);
 
-	gck_attributes_add_string (test->at.prv_attrs, CKA_ID, id);
-	handle = gck_mock_module_take_object (gck_attributes_ref (test->at.prv_attrs));
+	gck_builder_add_all (&builder, test->at.prv_attrs);
+	gck_builder_add_string (&builder, CKA_ID, id);
+	handle = gck_mock_module_take_object (gck_builder_end (&builder));
 	test->prv_object = gck_object_from_handle (test->mo.session, handle);
 }
 
@@ -527,6 +531,7 @@ perform_load_partial (TestLoading *test,
                       GckObject *original,
                       GckAttributes *attributes)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *partial;
 	GckObject *object;
 	GError *error = NULL;
@@ -534,9 +539,9 @@ perform_load_partial (TestLoading *test,
 	GNode *info;
 	guint i;
 
-	partial = gck_attributes_new ();
 	for (i = 0; i < gck_attributes_count (attributes); i += 2)
-		gck_attributes_add (partial, gck_attributes_at (attributes, i));
+		gck_builder_add_owned (&builder, gck_attributes_at (attributes, i));
+	partial = gck_builder_end (&builder);
 
 	object = g_object_new (mock_object_get_type (),
 	                       "module", test->mo.module,
@@ -607,16 +612,17 @@ static void
 test_load_failure_build (TestModule *test,
                          gconstpointer fixture)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GckAttributes *attributes;
 	const gulong INVALID = 0xFFF00FF; /* invalid handle, shouldn't be used */
 	GckObject *object;
 	GError *error = NULL;
 	GNode *info;
 
-	attributes = gck_attributes_new ();
-	gck_attributes_add_ulong (attributes, CKA_CLASS, CKO_CERTIFICATE);
-	gck_attributes_add_ulong (attributes, CKA_CERTIFICATE_TYPE, CKC_X_509);
-	gck_attributes_add_string (attributes, CKA_VALUE, "invalid value");
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
+	gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
+	gck_builder_add_string (&builder, CKA_VALUE, "invalid value");
+	attributes = gck_builder_end (&builder);
 
 	object = g_object_new (mock_object_get_type (),
 	                       "module", test->module,
diff --git a/gcr/tests/test-trust.c b/gcr/tests/test-trust.c
index 04147cd..905024d 100644
--- a/gcr/tests/test-trust.c
+++ b/gcr/tests/test-trust.c
@@ -268,21 +268,20 @@ test_is_certificate_anchored_not (Test *test, gconstpointer unused)
 static void
 test_is_certificate_anchored_yes (Test *test, gconstpointer unused)
 {
+	GckBuilder builder = GCK_BUILDER_INIT;
 	GError *error = NULL;
-	GckAttributes *attrs;
 	gconstpointer der;
 	gsize n_der;
 	gboolean ret;
 
 	/* Create a certificate root trust */
-	attrs = gck_attributes_new ();
 	der = gcr_certificate_get_der_data (test->certificate, &n_der);
-	gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, der, n_der);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION);
-	gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
-	gck_attributes_add_string (attrs, CKA_X_PURPOSE, GCR_PURPOSE_CLIENT_AUTH);
-	gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE);
-	gck_mock_module_take_object (attrs);
+	gck_builder_add_data (&builder, CKA_X_CERTIFICATE_VALUE, der, n_der);
+	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_X_TRUST_ASSERTION);
+	gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
+	gck_builder_add_string (&builder, CKA_X_PURPOSE, GCR_PURPOSE_CLIENT_AUTH);
+	gck_builder_add_ulong (&builder, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE);
+	gck_mock_module_take_object (gck_builder_end (&builder));
 
 	ret = gcr_trust_is_certificate_anchored (test->certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, &error);
 	g_assert (ret == TRUE);



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