[gnome-keyring/trust-store: 98/105] Implement trust assertions in pkcs11 modules.



commit e973a2bd20367d2a88a70e6f7f0643abdb56b646
Author: Stef Walter <stefw collabora co uk>
Date:   Fri Nov 19 19:33:39 2010 +0000

    Implement trust assertions in pkcs11 modules.
    
     * Change the format of trust stored in XDG store.
     * Introduce new assertion object.
     * Trust objects own multiple assertion objects.
     * Netscape style trust is implemented on assertion objects.

 pkcs11/gkm/Makefile.am                     |    3 +-
 pkcs11/gkm/gkm-assertion.c                 |  232 ++++++++++
 pkcs11/gkm/gkm-assertion.h                 |   66 +++
 pkcs11/gkm/gkm-attributes.c                |   36 ++
 pkcs11/gkm/gkm-attributes.h                |    5 +
 pkcs11/gkm/gkm-certificate-trust.c         |  377 ---------------
 pkcs11/gkm/gkm-certificate-trust.h         |   57 ---
 pkcs11/gkm/gkm-certificate.c               |  156 -------
 pkcs11/gkm/gkm-oids.h                      |   34 ++
 pkcs11/gkm/gkm-trust.c                     |  174 +++++++
 pkcs11/gkm/gkm-trust.h                     |   62 +++
 pkcs11/gkm/gkm-types.h                     |    3 +-
 pkcs11/gkm/gkm-util.c                      |   97 ++++
 pkcs11/gkm/gkm-util.h                      |   15 +
 pkcs11/pkcs11g.h                           |   50 --
 pkcs11/pkcs11i.h                           |   22 +
 pkcs11/roots-store/Makefile.am             |    3 +-
 pkcs11/roots-store/gkm-roots-certificate.c |   28 +-
 pkcs11/roots-store/gkm-roots-certificate.h |    3 +-
 pkcs11/roots-store/gkm-roots-trust.c       |  411 +++++++++++++++++
 pkcs11/roots-store/gkm-roots-trust.h       |   60 +++
 pkcs11/xdg-store/Makefile.am               |    1 +
 pkcs11/xdg-store/asn1-def-xdg.c            |   35 +-
 pkcs11/xdg-store/gkm-xdg-assertion.c       |  252 ++++++++++
 pkcs11/xdg-store/gkm-xdg-assertion.h       |   55 +++
 pkcs11/xdg-store/gkm-xdg-module.c          |   26 +-
 pkcs11/xdg-store/gkm-xdg-trust-netscape.c  |  314 +++++++++++++
 pkcs11/xdg-store/gkm-xdg-trust-netscape.h  |   59 +++
 pkcs11/xdg-store/gkm-xdg-trust.c           |  691 +++++++++++++---------------
 pkcs11/xdg-store/gkm-xdg-trust.h           |   15 +-
 pkcs11/xdg-store/xdg.asn                   |   33 +-
 31 files changed, 2297 insertions(+), 1078 deletions(-)
---
diff --git a/pkcs11/gkm/Makefile.am b/pkcs11/gkm/Makefile.am
index 47ee90b..c618480 100644
--- a/pkcs11/gkm/Makefile.am
+++ b/pkcs11/gkm/Makefile.am
@@ -19,10 +19,10 @@ BUILT_SOURCES = \
 libgkm_la_SOURCES = \
 	gkm-aes-key.c gkm-aes-key.h \
 	gkm-aes-mechanism.c gkm-aes-mechanism.h \
+	gkm-assertion.c gkm-assertion.h \
 	gkm-attributes.c gkm-attributes.h \
 	gkm-certificate.c gkm-certificate.h \
 	gkm-certificate-key.c gkm-certificate-key.h \
-	gkm-certificate-trust.c gkm-certificate-trust.h \
 	gkm-credential.c gkm-credential.h \
 	gkm-crypto.c gkm-crypto.h \
 	gkm-data-asn1.c gkm-data-asn1.h \
@@ -55,6 +55,7 @@ libgkm_la_SOURCES = \
 	gkm-test.c gkm-test.h \
 	gkm-timer.c gkm-timer.h \
 	gkm-transaction.c gkm-transaction.h \
+	gkm-trust.c gkm-trust.h \
 	gkm-types.h \
 	gkm-util.c gkm-util.h \
 	$(BUILT_SOURCES)
diff --git a/pkcs11/gkm/gkm-assertion.c b/pkcs11/gkm/gkm-assertion.c
new file mode 100644
index 0000000..2754c99
--- /dev/null
+++ b/pkcs11/gkm/gkm-assertion.c
@@ -0,0 +1,232 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkm-assertion.h"
+#include "gkm-attributes.h"
+#include "gkm-object.h"
+#include "gkm-trust.h"
+#include "gkm-util.h"
+
+#include "pkcs11/pkcs11g.h"
+#include "pkcs11/pkcs11i.h"
+
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_TRUST,
+	PROP_TYPE,
+	PROP_PURPOSE,
+	PROP_REMOTE
+};
+
+struct _GkmAssertionPrivate {
+	GkmTrust *trust;
+	gulong type;
+	gchar *purpose;
+	gchar *remote;
+};
+
+G_DEFINE_TYPE (GkmAssertion, gkm_assertion, GKM_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gkm_assertion_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+	GkmAssertion *self = GKM_ASSERTION (base);
+
+	switch (attr->type)
+	{
+	case CKA_PRIVATE:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+	case CKA_CLASS:
+		return gkm_attribute_set_ulong (attr, CKO_G_TRUST_ASSERTION);
+	case CKA_MODIFIABLE:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+
+	/* Various trust flags */
+	case CKA_G_ASSERTION_TYPE:
+		return gkm_attribute_set_ulong (attr, self->pv->type);
+	case CKA_G_PURPOSE:
+		return gkm_attribute_set_string (attr, self->pv->purpose);
+	case CKA_G_REMOTE:
+		if (!self->pv->remote)
+			return CKR_ATTRIBUTE_TYPE_INVALID;
+		return gkm_attribute_set_string (attr, self->pv->remote);
+
+	/* Certificate reference values */
+	case CKA_SERIAL_NUMBER:
+	case CKA_ISSUER:
+	case CKA_G_CERTIFICATE_VALUE:
+		return gkm_object_get_attribute (GKM_OBJECT (self->pv->trust), session, attr);
+
+	default:
+		break;
+	};
+
+	return GKM_OBJECT_CLASS (gkm_assertion_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gkm_assertion_init (GkmAssertion *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKM_TYPE_ASSERTION, GkmAssertionPrivate);
+}
+
+static void
+gkm_assertion_finalize (GObject *obj)
+{
+	GkmAssertion *self = GKM_ASSERTION (obj);
+
+	if (self->pv->trust)
+		g_object_remove_weak_pointer (G_OBJECT (self->pv->trust), (gpointer*)&(self->pv->trust));
+	self->pv->trust = NULL;
+
+	g_free (self->pv->purpose);
+	self->pv->purpose = NULL;
+
+	g_free (self->pv->remote);
+	self->pv->remote = NULL;
+
+	G_OBJECT_CLASS (gkm_assertion_parent_class)->finalize (obj);
+}
+
+
+static void
+gkm_assertion_set_property (GObject *obj, guint prop_id, const GValue *value,
+                            GParamSpec *pspec)
+{
+	GkmAssertion *self = GKM_ASSERTION (obj);
+
+	switch (prop_id) {
+	case PROP_TRUST:
+		g_return_if_fail (!self->pv->trust);
+		self->pv->trust = g_value_get_object (value);
+		g_return_if_fail (self->pv->trust);
+		g_object_add_weak_pointer (G_OBJECT (self->pv->trust), (gpointer*)&(self->pv->trust));
+		break;
+	case PROP_TYPE:
+		self->pv->type = g_value_get_ulong (value);
+		break;
+	case PROP_PURPOSE:
+		self->pv->purpose = g_value_dup_string (value);
+		break;
+	case PROP_REMOTE:
+		self->pv->remote = g_value_dup_string (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gkm_assertion_get_property (GObject *obj, guint prop_id, GValue *value,
+                            GParamSpec *pspec)
+{
+	GkmAssertion *self = GKM_ASSERTION (obj);
+
+	switch (prop_id) {
+	case PROP_TRUST:
+		g_value_set_object (value, gkm_assertion_get_trust_object (self));
+		break;
+	case PROP_TYPE:
+		g_value_set_ulong (value, gkm_assertion_get_trust_type (self));
+		break;
+	case PROP_PURPOSE:
+		g_value_set_string (value, gkm_assertion_get_purpose (self));
+		break;
+	case PROP_REMOTE:
+		g_value_set_string (value, gkm_assertion_get_remote (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gkm_assertion_class_init (GkmAssertionClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
+
+	gobject_class->finalize = gkm_assertion_finalize;
+	gobject_class->set_property = gkm_assertion_set_property;
+	gobject_class->get_property = gkm_assertion_get_property;
+
+	gkm_class->get_attribute = gkm_assertion_get_attribute;
+
+	g_type_class_add_private (klass, sizeof (GkmAssertionPrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GkmAssertion*
+gkm_assertion_new (GkmTrust *trust, gulong type, const gchar *purpose, const gchar *remote)
+{
+	return g_object_new (GKM_TYPE_ASSERTION,
+	                     "trust", trust,
+	                     "type", type,
+	                     "purpose", purpose,
+	                     "remote", remote,
+	                     NULL);
+}
+
+const gchar*
+gkm_assertion_get_purpose (GkmAssertion *self)
+{
+	g_return_val_if_fail (GKM_IS_ASSERTION (self), NULL);
+	return self->pv->purpose;
+}
+
+const gchar*
+gkm_assertion_get_remote (GkmAssertion *self)
+{
+	g_return_val_if_fail (GKM_IS_ASSERTION (self), NULL);
+	return self->pv->remote;
+}
+
+gulong
+gkm_assertion_get_trust_type (GkmAssertion *self)
+{
+	g_return_val_if_fail (GKM_IS_ASSERTION (self), 0UL);
+	return self->pv->type;
+}
+
+GkmTrust*
+gkm_assertion_get_trust_object (GkmAssertion *self)
+{
+	g_return_val_if_fail (GKM_IS_ASSERTION (self), NULL);
+	return self->pv->trust;
+}
diff --git a/pkcs11/gkm/gkm-assertion.h b/pkcs11/gkm/gkm-assertion.h
new file mode 100644
index 0000000..d9cfe7e
--- /dev/null
+++ b/pkcs11/gkm/gkm-assertion.h
@@ -0,0 +1,66 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ * Copyright (C) 2010 Collabora Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKM_ASSERTION_H__
+#define __GKM_ASSERTION_H__
+
+#include <glib-object.h>
+
+#include "gkm-object.h"
+#include "gkm-types.h"
+
+#define GKM_FACTORY_ASSERTION            (gkm_assertion_get_factory ())
+#define GKM_TYPE_ASSERTION               (gkm_assertion_get_type ())
+#define GKM_ASSERTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_TYPE_ASSERTION, GkmAssertion))
+#define GKM_ASSERTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_TYPE_ASSERTION, GkmAssertionClass))
+#define GKM_IS_ASSERTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_TYPE_ASSERTION))
+#define GKM_IS_ASSERTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_TYPE_ASSERTION))
+#define GKM_ASSERTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_TYPE_ASSERTION, GkmAssertionClass))
+
+typedef struct _GkmAssertionClass GkmAssertionClass;
+typedef struct _GkmAssertionPrivate GkmAssertionPrivate;
+
+struct _GkmAssertion {
+	GkmObject parent;
+	GkmAssertionPrivate *pv;
+};
+
+struct _GkmAssertionClass {
+	GkmObjectClass parent_class;
+};
+
+GType                 gkm_assertion_get_type               (void);
+
+GkmAssertion*         gkm_assertion_new                    (GkmTrust *trust,
+                                                            gulong trust_type,
+                                                            const gchar *purpose,
+                                                            const gchar *remote);
+
+const gchar*          gkm_assertion_get_purpose            (GkmAssertion *self);
+
+const gchar*          gkm_assertion_get_remote             (GkmAssertion *self);
+
+gulong                gkm_assertion_get_trust_type         (GkmAssertion *self);
+
+GkmTrust*             gkm_assertion_get_trust_object       (GkmAssertion *self);
+
+#endif /* __GKM_ASSERTION_H__ */
diff --git a/pkcs11/gkm/gkm-attributes.c b/pkcs11/gkm/gkm-attributes.c
index e4d571a..8aff557 100644
--- a/pkcs11/gkm/gkm-attributes.c
+++ b/pkcs11/gkm/gkm-attributes.c
@@ -349,6 +349,42 @@ gkm_attribute_set_template (CK_ATTRIBUTE_PTR attr, GArray *template)
 	return rv;
 }
 
+CK_RV
+gkm_attribute_set_checksum (CK_ATTRIBUTE_PTR attr, GChecksumType ctype,
+                            gconstpointer data, gsize n_data)
+{
+	GChecksum *checksum;
+	gssize length;
+	gsize result;
+
+	g_assert (attr);
+
+	g_return_val_if_fail (data, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (n_data, CKR_GENERAL_ERROR);
+
+	length = g_checksum_type_get_length (ctype);
+	g_return_val_if_fail (length < 0, CKR_GENERAL_ERROR);
+
+	/* Just asking for the length */
+	if (!attr->pValue) {
+		attr->ulValueLen = length;
+		return CKR_OK;
+	}
+
+	/* Buffer is too short */
+	if (length > attr->ulValueLen) {
+		attr->ulValueLen = length;
+		return CKR_BUFFER_TOO_SMALL;
+	}
+
+	checksum = g_checksum_new (ctype);
+	g_checksum_update (checksum, data, n_data);
+	result = attr->ulValueLen;
+	g_checksum_get_digest (checksum, attr->pValue, &result);
+	attr->ulValueLen = result;
+	return CKR_OK;
+}
+
 gboolean
 gkm_attribute_equal (gconstpointer v1, gconstpointer v2)
 {
diff --git a/pkcs11/gkm/gkm-attributes.h b/pkcs11/gkm/gkm-attributes.h
index 97088d4..4315940 100644
--- a/pkcs11/gkm/gkm-attributes.h
+++ b/pkcs11/gkm/gkm-attributes.h
@@ -73,6 +73,11 @@ CK_RV                 gkm_attribute_set_mpi                            (CK_ATTRI
 CK_RV                 gkm_attribute_set_template                       (CK_ATTRIBUTE_PTR attr,
                                                                         GArray *template);
 
+CK_RV                 gkm_attribute_set_checksum                       (CK_ATTRIBUTE_PTR attr,
+                                                                        GChecksumType ctype,
+                                                                        gconstpointer data,
+                                                                        gsize n_data);
+
 guint                 gkm_attribute_hash                               (gconstpointer v);
 
 gboolean              gkm_attribute_equal                              (gconstpointer a,
diff --git a/pkcs11/gkm/gkm-certificate.c b/pkcs11/gkm/gkm-certificate.c
index 910c365..4c45340 100644
--- a/pkcs11/gkm/gkm-certificate.c
+++ b/pkcs11/gkm/gkm-certificate.c
@@ -61,17 +61,6 @@ struct _GkmCertificatePrivate {
 static GQuark OID_BASIC_CONSTRAINTS;
 static GQuark OID_ENHANCED_USAGE;
 
-static GQuark OID_USAGE_SSH_AUTH;
-static GQuark OID_USAGE_SERVER_AUTH;
-static GQuark OID_USAGE_CLIENT_AUTH;
-static GQuark OID_USAGE_CODE_SIGNING;
-static GQuark OID_USAGE_EMAIL;
-static GQuark OID_USAGE_TIME_STAMPING;
-static GQuark OID_USAGE_IPSEC_ENDPOINT;
-static GQuark OID_USAGE_IPSEC_TUNNEL;
-static GQuark OID_USAGE_IPSEC_USER;
-static GQuark OID_USAGE_IKE_INTERMEDIATE;
-
 static void gkm_certificate_serializable (GkmSerializableIface *iface);
 
 G_DEFINE_TYPE_EXTENDED (GkmCertificate, gkm_certificate, GKM_TYPE_OBJECT, 0,
@@ -93,123 +82,12 @@ init_quarks (void)
 		QUARK (OID_BASIC_CONSTRAINTS, "2.5.29.19");
 		QUARK (OID_ENHANCED_USAGE, "2.5.29.37");
 
-		QUARK (OID_USAGE_SSH_AUTH, "ssh-authentication");
-		QUARK (OID_USAGE_SERVER_AUTH, "1.3.6.1.5.5.7.3.1");
-		QUARK (OID_USAGE_CLIENT_AUTH, "1.3.6.1.5.5.7.3.2");
-		QUARK (OID_USAGE_CODE_SIGNING, "1.3.6.1.5.5.7.3.3");
-		QUARK (OID_USAGE_EMAIL, "1.3.6.1.5.5.7.3.4");
-		QUARK (OID_USAGE_TIME_STAMPING, "1.3.6.1.5.5.7.3.8");
-		QUARK (OID_USAGE_IPSEC_ENDPOINT, "1.3.6.1.5.5.7.3.5");
-		QUARK (OID_USAGE_IPSEC_TUNNEL, "1.3.6.1.5.5.7.3.6");
-		QUARK (OID_USAGE_IPSEC_USER, "1.3.6.1.5.5.7.3.7");
-		QUARK (OID_USAGE_IKE_INTERMEDIATE, "1.3.6.1.5.5.8.2.2");
-
 		#undef QUARK
 
 		g_once_init_leave (&quarks_inited, 1);
 	}
 }
 
-static gboolean
-has_certificate_purposes (GkmCertificate *self)
-{
-	const guchar *extension;
-	gsize n_extension;
-
-	/* TODO: Storage of certificate purposes in the store */
-
-	extension = gkm_certificate_get_extension (self, OID_ENHANCED_USAGE, &n_extension, NULL);
-	return extension != NULL;
-}
-
-static CK_RV
-lookup_certificate_purposes (GkmCertificate *self, GQuark **oids)
-{
-	GkmDataResult res;
-	const guchar *extension;
-	gsize n_extension;
-
-	*oids = NULL;
-
-	/* TODO: Storage of certificate purposes in the store */
-
-	extension = gkm_certificate_get_extension (self, OID_ENHANCED_USAGE, &n_extension, NULL);
-
-	/* No enhanced usage noted, any are allowed */
-	if (!extension)
-		return CKR_OK;
-
-	res = gkm_data_der_read_enhanced_usage (extension, n_extension, oids);
-
-	if (res != GKM_DATA_SUCCESS)
-		return CKR_GENERAL_ERROR;
-
-	return CKR_OK;
-}
-
-
-static gboolean
-check_certificate_purpose (GkmCertificate *self, GQuark oid)
-{
-	GQuark *usages, *usage;
-	gboolean ret;
-
-	if (lookup_certificate_purposes (self, &usages) != CKR_OK)
-		return FALSE;
-
-	/* No usages noted, any are allowed */
-	if (!usages)
-		return TRUE;
-
-	ret = FALSE;
-	for (usage = usages; *usage; ++usage) {
-		if (*usage == oid) {
-			ret = TRUE;
-			break;
-		}
-	}
-
-	g_free (usages);
-
-	return ret;
-}
-
-static CK_RV
-read_certificate_purpose (GkmCertificate *self, GQuark oid, CK_ATTRIBUTE_PTR attr)
-{
-	gboolean value = check_certificate_purpose (self, oid);
-	gkm_attribute_set_bool (attr, value);
-	return CKR_OK;
-}
-
-
-static CK_RV
-read_certificate_purposes (GkmCertificate *self, CK_ATTRIBUTE_PTR attr)
-{
-	GQuark *purposes, *purpose;
-	GString *result;
-	CK_RV ret;
-
-	ret = lookup_certificate_purposes (self, &purposes);
-	if (ret != CKR_OK)
-		return ret;
-
-	/* Convert into a space delimited string */
-	result = g_string_sized_new (128);
-	for (purpose = purposes; purpose && *purpose; ++purpose) {
-		g_string_append (result, g_quark_to_string (*purpose));
-		g_string_append_c (result, ' ');
-	}
-
-	g_free (purposes);
-
-	gkm_attribute_set_string (attr, result->str);
-	g_string_free (result, TRUE);
-
-	return CKR_OK;
-}
-
-
 static gint
 find_certificate_extension (GkmCertificate *self, GQuark oid)
 {
@@ -369,40 +247,6 @@ gkm_certificate_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATT
 	/* What in the world is this doing in the spec? */
 	case CKA_JAVA_MIDP_SECURITY_DOMAIN:
 		return gkm_attribute_set_ulong (attr, 0); /* 0 = unspecified */
-
-	case CKA_GNOME_PURPOSE_RESTRICTED:
-		gkm_attribute_set_bool (attr, has_certificate_purposes (self));
-		return CKR_OK;
-
-	case CKA_GNOME_PURPOSE_OIDS:
-		return read_certificate_purposes (self, attr);
-
-	case CKA_GNOME_PURPOSE_SSH_AUTH:
-		return read_certificate_purpose (self, OID_USAGE_SSH_AUTH, attr);
-
-	case CKA_GNOME_PURPOSE_SERVER_AUTH:
-		return read_certificate_purpose (self, OID_USAGE_SERVER_AUTH, attr);
-
-	case CKA_GNOME_PURPOSE_CLIENT_AUTH:
-		return read_certificate_purpose (self, OID_USAGE_CLIENT_AUTH, attr);
-
-	case CKA_GNOME_PURPOSE_CODE_SIGNING:
-		return read_certificate_purpose (self, OID_USAGE_CODE_SIGNING, attr);
-
-	case CKA_GNOME_PURPOSE_EMAIL_PROTECTION:
-		return read_certificate_purpose (self, OID_USAGE_EMAIL, attr);
-
-	case CKA_GNOME_PURPOSE_IPSEC_END_SYSTEM:
-		return read_certificate_purpose (self, OID_USAGE_IPSEC_ENDPOINT, attr);
-
-	case CKA_GNOME_PURPOSE_IPSEC_TUNNEL:
-		return read_certificate_purpose (self, OID_USAGE_IPSEC_TUNNEL, attr);
-
-	case CKA_GNOME_PURPOSE_IPSEC_USER:
-		return read_certificate_purpose (self, OID_USAGE_IPSEC_USER, attr);
-
-	case CKA_GNOME_PURPOSE_TIME_STAMPING:
-		return read_certificate_purpose (self, OID_USAGE_TIME_STAMPING, attr);
 	};
 
 	return GKM_OBJECT_CLASS (gkm_certificate_parent_class)->get_attribute (base, session, attr);
diff --git a/pkcs11/gkm/gkm-oids.h b/pkcs11/gkm/gkm-oids.h
new file mode 100644
index 0000000..011d748
--- /dev/null
+++ b/pkcs11/gkm/gkm-oids.h
@@ -0,0 +1,34 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKM_OIDS_H__
+#define __GKM_OIDS_H__
+
+#define GKM_OID_EXTUSAGE_SERVER_AUTH "1.3.6.1.5.5.7.3.1"
+#define GKM_OID_EXTUSAGE_CLIENT_AUTH "1.3.6.1.5.5.7.3.2"
+#define GKM_OID_EXTUSAGE_CODE_SIGNING "1.3.6.1.5.5.7.3.3"
+#define GKM_OID_EXTUSAGE_EMAIL "1.3.6.1.5.5.7.3.4"
+#define GKM_OID_EXTUSAGE_IPSEC_ENDPOINT "1.3.6.1.5.5.7.3.5"
+#define GKM_OID_EXTUSAGE_IPSEC_TUNNEL "1.3.6.1.5.5.7.3.6"
+#define GKM_OID_EXTUSAGE_IPSEC_USER "1.3.6.1.5.5.7.3.7"
+#define GKM_OID_EXTUSAGE_TIME_STAMPING "1.3.6.1.5.5.7.3.8"
+
+#endif /* __GKM_OIDS_H__ */
diff --git a/pkcs11/gkm/gkm-trust.c b/pkcs11/gkm/gkm-trust.c
new file mode 100644
index 0000000..5389429
--- /dev/null
+++ b/pkcs11/gkm/gkm-trust.c
@@ -0,0 +1,174 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkm-trust.h"
+
+#include "gkm-attributes.h"
+#include "gkm-object.h"
+#include "gkm-oids.h"
+
+#include "pkcs11/pkcs11n.h"
+#include "pkcs11/pkcs11i.h"
+
+#include <glib/gi18n.h>
+
+G_DEFINE_TYPE (GkmTrust, gkm_trust, GKM_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static CK_RV
+trust_get_usage (GkmTrust *self, const gchar *purpose, CK_ATTRIBUTE_PTR attr)
+{
+	GkmTrustLevel level;
+	CK_ULONG trust;
+
+	level = gkm_trust_get_level_for_purpose (self, purpose);
+
+	switch (level) {
+	case GKM_TRUST_UNKNOWN:
+		trust = CKT_NETSCAPE_TRUST_UNKNOWN;
+		break;
+	case GKM_TRUST_UNTRUSTED:
+		trust = CKT_NETSCAPE_UNTRUSTED;
+		break;
+	case GKM_TRUST_TRUSTED:
+		trust = CKT_NETSCAPE_TRUSTED;
+		break;
+	case GKM_TRUST_ANCHOR:
+		trust = CKT_NETSCAPE_TRUSTED_DELEGATOR;
+		break;
+	default:
+		g_return_val_if_reached (CKR_GENERAL_ERROR);
+	};
+
+	return gkm_attribute_set_ulong (attr, trust);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gkm_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+	GkmTrust *self = GKM_TRUST (base);
+
+	/*
+	 * This object exposes a netscape compatible trust object. However the
+	 * primary interface for dealing with trust is through GkmAssertion objects.
+	 */
+
+	switch (attr->type)
+	{
+	case CKA_PRIVATE:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+	case CKA_TRUST_STEP_UP_APPROVED:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+	case CKA_CLASS:
+		return gkm_attribute_set_ulong (attr, CKO_NETSCAPE_TRUST);
+	case CKA_MODIFIABLE:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+
+	/*
+	 * TODO: Is it even useful to support overriding from certificate
+	 * defaults? For now we just return unknown for all of them, and
+	 * the caller should use whatever's in the certificate.
+	 */
+	case CKA_TRUST_DIGITAL_SIGNATURE:
+	case CKA_TRUST_NON_REPUDIATION:
+	case CKA_TRUST_KEY_ENCIPHERMENT:
+	case CKA_TRUST_DATA_ENCIPHERMENT:
+	case CKA_TRUST_KEY_AGREEMENT:
+	case CKA_TRUST_KEY_CERT_SIGN:
+	case CKA_TRUST_CRL_SIGN:
+		return gkm_attribute_set_ulong (attr, CKT_NETSCAPE_TRUST_UNKNOWN);
+
+	/* Various trust flags */
+	case CKA_TRUST_SERVER_AUTH:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_SERVER_AUTH, attr);
+	case CKA_TRUST_CLIENT_AUTH:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_CLIENT_AUTH, attr);
+	case CKA_TRUST_CODE_SIGNING:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_CODE_SIGNING, attr);
+	case CKA_TRUST_EMAIL_PROTECTION:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_EMAIL, attr);
+	case CKA_TRUST_IPSEC_END_SYSTEM:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_IPSEC_ENDPOINT, attr);
+	case CKA_TRUST_IPSEC_TUNNEL:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_IPSEC_TUNNEL, attr);
+	case CKA_TRUST_IPSEC_USER:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_IPSEC_USER, attr);
+	case CKA_TRUST_TIME_STAMPING:
+		return trust_get_usage (self, GKM_OID_EXTUSAGE_TIME_STAMPING, attr);
+
+	/* Certificate reference values */
+	case CKA_SUBJECT:
+	case CKA_SERIAL_NUMBER:
+	case CKA_ISSUER:
+	case CKA_CERT_MD5_HASH:
+	case CKA_CERT_SHA1_HASH:
+		g_warning ("derived class should have provided these attributes");
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	default:
+		break;
+	};
+
+	return GKM_OBJECT_CLASS (gkm_trust_parent_class)->get_attribute (base, session, attr);
+}
+
+static GkmTrustLevel
+gkm_trust_real_get_trust_level (GkmTrust *self, const gchar *purpose)
+{
+	return GKM_TRUST_UNKNOWN;
+}
+
+static void
+gkm_trust_init (GkmTrust *self)
+{
+	/* For future expansion */
+	self->pv = NULL;
+}
+
+static void
+gkm_trust_class_init (GkmTrustClass *klass)
+{
+	GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
+	gkm_class->get_attribute = gkm_trust_get_attribute;
+	klass->get_trust_level = gkm_trust_real_get_trust_level;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GkmTrustLevel
+gkm_trust_get_level_for_purpose (GkmTrust *self, const gchar *purpose)
+{
+	g_return_val_if_fail (GKM_IS_TRUST (self), GKM_TRUST_UNKNOWN);
+	g_return_val_if_fail (purpose, GKM_TRUST_UNKNOWN);
+	g_assert (GKM_TRUST_GET_CLASS (self)->get_trust_level);
+	return GKM_TRUST_GET_CLASS (self)->get_trust_level (self, purpose);
+}
diff --git a/pkcs11/gkm/gkm-trust.h b/pkcs11/gkm/gkm-trust.h
new file mode 100644
index 0000000..7bb1f15
--- /dev/null
+++ b/pkcs11/gkm/gkm-trust.h
@@ -0,0 +1,62 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKM_TRUST_H__
+#define __GKM_TRUST_H__
+
+#include <glib-object.h>
+
+#include "gkm-object.h"
+
+typedef enum _GkmTrustLevel {
+	GKM_TRUST_UNKNOWN = 0,
+	GKM_TRUST_UNTRUSTED = 1,
+	GKM_TRUST_TRUSTED = 2,
+	GKM_TRUST_ANCHOR = 3,
+} GkmTrustLevel;
+
+#define GKM_FACTORY_TRUST            (gkm_trust_get_factory ())
+#define GKM_TYPE_TRUST               (gkm_trust_get_type ())
+#define GKM_TRUST(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_TYPE_TRUST, GkmTrust))
+#define GKM_TRUST_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_TYPE_TRUST, GkmTrustClass))
+#define GKM_IS_TRUST(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_TYPE_TRUST))
+#define GKM_IS_TRUST_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_TYPE_TRUST))
+#define GKM_TRUST_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_TYPE_TRUST, GkmTrustClass))
+
+typedef struct _GkmTrustClass GkmTrustClass;
+typedef struct _GkmTrustPrivate GkmTrustPrivate;
+
+struct _GkmTrust {
+	GkmObject parent;
+	GkmTrustPrivate *pv;
+};
+
+struct _GkmTrustClass {
+	GkmObjectClass parent_class;
+
+	GkmTrustLevel (*get_trust_level) (GkmTrust *self, const gchar *purpose);
+};
+
+GType                 gkm_trust_get_type               (void);
+
+GkmTrustLevel         gkm_trust_get_level_for_purpose  (GkmTrust *self, const gchar *purpose);
+
+#endif /* __GKM_TRUST_H__ */
diff --git a/pkcs11/gkm/gkm-types.h b/pkcs11/gkm/gkm-types.h
index 386fd4c..4ed1c4c 100644
--- a/pkcs11/gkm/gkm-types.h
+++ b/pkcs11/gkm/gkm-types.h
@@ -23,9 +23,9 @@
 #define __GKM_TYPES_H__
 
 typedef struct _GkmAesKey GkmAesKey;
+typedef struct _GkmAssertion GkmAssertion;
 typedef struct _GkmCertificate GkmCertificate;
 typedef struct _GkmCertificateKey GkmCertificateKey;
-typedef struct _GkmCertificateTrust GkmCertificateTrust;
 typedef struct _GkmCredential GkmCredential;
 typedef struct _GkmDhKey GkmDhKey;
 typedef struct _GkmDhPrivateKey GkmDhPrivateKey;
@@ -47,5 +47,6 @@ typedef struct _GkmSexpKey GkmSexpKey;
 typedef struct _GkmStore GkmStore;
 typedef struct _GkmTimer GkmTimer;
 typedef struct _GkmTransaction GkmTransaction;
+typedef struct _GkmTrust GkmTrust;
 
 #endif /* __GKM_TYPES_H__ */
diff --git a/pkcs11/gkm/gkm-util.c b/pkcs11/gkm/gkm-util.c
index 26fca33..6e1f29c 100644
--- a/pkcs11/gkm/gkm-util.c
+++ b/pkcs11/gkm/gkm-util.c
@@ -19,6 +19,41 @@
  * 02111-1307, USA.
  */
 
+/*
+ * PORTIONS FROM: ----------------------------------------------------------
+ *
+ * GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * --------------------------------------------------------------------------
+ */
+
+/*
+ * PORTIONS FROM: ----------------------------------------------------------
+ *
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ *
+ * --------------------------------------------------------------------------
+ */
+
 #include "config.h"
 
 #include "gkm-util.h"
@@ -32,6 +67,68 @@
 /* Only access using atomic operations */
 static gint next_handle = 0x00000010;
 
+GkmMemory*
+gkm_util_memory_new (gconstpointer data, gsize n_data)
+{
+	GkmMemory *memory;
+
+	memory = g_malloc (n_data + sizeof (GkmMemory));
+	memory->n_data = n_data;
+	memory->data = memory + 1;
+
+	if (n_data) {
+		g_assert (data);
+		memcpy (memory + 1, data, n_data);
+	}
+
+	return memory;
+}
+
+guint
+gkm_util_memory_hash (gconstpointer v)
+{
+	const GkmMemory *memory = v;
+	const signed char *p;
+	guint32 h = 0;
+	gsize i;
+
+	g_assert (memory);
+	g_assert (memory->data);
+	p = memory->data;
+
+	/* 31 bit hash function */
+	for (i = 0; i < memory->n_data; ++i, ++p)
+		h = (h << 5) - h + *p;
+
+	return h;
+}
+
+gboolean
+gkm_util_memory_equal (gconstpointer v1, gconstpointer v2)
+{
+	const GkmMemory *memory_1 = v1;
+	const GkmMemory *memory_2 = v2;
+
+	if (memory_1 == memory_2)
+		return TRUE;
+	if (!memory_1 || !memory_2)
+		return FALSE;
+
+	if (memory_1->n_data != memory_2->n_data)
+		return FALSE;
+
+	g_assert (memory_1->data);
+	g_assert (memory_2->data);
+
+	return (memcmp (memory_1->data, memory_2->data, memory_1->n_data) == 0);
+}
+
+void
+gkm_util_memory_free (gpointer memory)
+{
+	g_free (memory);
+}
+
 gulong*
 gkm_util_ulong_alloc (gulong value)
 {
diff --git a/pkcs11/gkm/gkm-util.h b/pkcs11/gkm/gkm-util.h
index b44a978..2a645b6 100644
--- a/pkcs11/gkm/gkm-util.h
+++ b/pkcs11/gkm/gkm-util.h
@@ -28,6 +28,21 @@
 
 #include "pkcs11/pkcs11.h"
 
+typedef struct _GkmMemory {
+	gconstpointer data;
+	gsize n_data;
+} GkmMemory;
+
+GkmMemory*            gkm_util_memory_new                         (gconstpointer data,
+                                                                   gsize n_data);
+
+guint                 gkm_util_memory_hash                        (gconstpointer memory);
+
+gboolean              gkm_util_memory_equal                       (gconstpointer memory_1,
+                                                                   gconstpointer memory_2);
+
+void                  gkm_util_memory_free                        (gpointer memory);
+
 guint                 gkm_util_ulong_hash                         (gconstpointer ptr_to_ulong);
 
 gboolean              gkm_util_ulong_equal                        (gconstpointer ptr_to_ulong_1,
diff --git a/pkcs11/pkcs11g.h b/pkcs11/pkcs11g.h
index c01a3c9..48be2e3 100644
--- a/pkcs11/pkcs11g.h
+++ b/pkcs11/pkcs11g.h
@@ -40,56 +40,6 @@
 #define CKA_GNOME_UNIQUE                            (CKA_GNOME + 350)
 
 /* -------------------------------------------------------------------
- * PURPOSES
- */
-
-/*
- * Whether the key or certificate is restricted to a set of
- * purposes (ie: enhanced usages).
- *
- * CK_BBOOL
- *
- *  - When CK_TRUE see CKA_PURPOSE_OIDS for the set of purposes.
- *  - When CK_FALSE then is not restricted to any specific purpose.
- */
-#define CKA_GNOME_PURPOSE_RESTRICTED             (CKA_GNOME + 12)
-
-/*
- * The available purposes that a certificate or key can be
- * used for.
- *
- * CK_STRING
- *
- *  - This is only relevant if CKA_PURPOSE_RESTRICTED is CK_TRUE.
- *  - Use CKA_TRUSTED and CKA_CERTIFICATE_CATEGORY to validate whether
- *    usage of the certificate for these purposes is directly or
- *    indirectly trusted by the user.
- *  - The returned string is a space delemited set of OIDs.
- *  - When an empty string is returned then no purposes are valid.
- */
-#define CKA_GNOME_PURPOSE_OIDS                   (CKA_GNOME + 11)
-
-/*
- * The key or certificate can be used for the purpose
- * indicated
- *
- * CK_BBOOL
- *
- *  - These are shortcuts to using CKA_PURPOSE_OIDS
- *  - Use CKA_TRUSTED and CKA_CERTIFICATE_CATEGORY to validate whether
- *    the certificate is directly or indirectly trusted by the user.
- */
-#define CKA_GNOME_PURPOSE_SSH_AUTH               (CKA_GNOME + 101)
-#define CKA_GNOME_PURPOSE_SERVER_AUTH            (CKA_GNOME + 102)
-#define CKA_GNOME_PURPOSE_CLIENT_AUTH            (CKA_GNOME + 103)
-#define CKA_GNOME_PURPOSE_CODE_SIGNING           (CKA_GNOME + 104)
-#define CKA_GNOME_PURPOSE_EMAIL_PROTECTION       (CKA_GNOME + 105)
-#define CKA_GNOME_PURPOSE_IPSEC_END_SYSTEM       (CKA_GNOME + 106)
-#define CKA_GNOME_PURPOSE_IPSEC_TUNNEL           (CKA_GNOME + 107)
-#define CKA_GNOME_PURPOSE_IPSEC_USER             (CKA_GNOME + 108)
-#define CKA_GNOME_PURPOSE_TIME_STAMPING          (CKA_GNOME + 109)
-
-/* -------------------------------------------------------------------
  */
 
 #define CKA_GNOME_TRANSIENT                      (CKA_GNOME + 201)
diff --git a/pkcs11/pkcs11i.h b/pkcs11/pkcs11i.h
index 44f285a..9e23ef5 100644
--- a/pkcs11/pkcs11i.h
+++ b/pkcs11/pkcs11i.h
@@ -119,4 +119,26 @@ typedef CK_G_APPLICATION* CK_G_APPLICATION_PTR;
 
 #define CKA_G_CREDENTIAL_TEMPLATE                (CKA_GNOME + 205)
 
+/* -------------------------------------------------------------------
+ * TRUST ASSERTIONS
+ */
+
+#define CKO_G_TRUST_ASSERTION                    (CKO_GNOME + 400)
+
+#define CKA_G_ASSERTION_TYPE                     (CKO_GNOME + 401)
+
+#define CKA_G_CERTIFICATE_VALUE                  (CKO_GNOME + 402)
+
+#define CKA_G_PURPOSE                            (CKO_GNOME + 403)
+
+#define CKA_G_REMOTE                             (CKO_GNOME + 404)
+
+typedef CK_ULONG CK_ASSERTION_TYPE;
+
+#define CKT_G_CERTIFICATE_UNTRUSTED              1UL
+
+#define CKT_G_CERTIFICATE_TRUST_EXCEPTION        2UL
+
+#define CKT_G_CERTIFICATE_TRUST_ANCHOR           3UL
+
 #endif /* PKCS11I_H */
diff --git a/pkcs11/roots-store/Makefile.am b/pkcs11/roots-store/Makefile.am
index 5d6108b..759cff8 100644
--- a/pkcs11/roots-store/Makefile.am
+++ b/pkcs11/roots-store/Makefile.am
@@ -17,7 +17,8 @@ noinst_LTLIBRARIES = \
 libgkm_roots_store_la_SOURCES = \
 	gkm-roots-store.h \
 	gkm-roots-module.c gkm-roots-module.h \
-	gkm-roots-certificate.c gkm-roots-certificate.h
+	gkm-roots-certificate.c gkm-roots-certificate.h \
+	gkm-roots-trust.c gkm-roots-trust.h
 
 # ------------------------------------------------------------------------------
 # The standalone module
diff --git a/pkcs11/roots-store/gkm-roots-certificate.c b/pkcs11/roots-store/gkm-roots-certificate.c
index 8499ec4..e2febaf 100644
--- a/pkcs11/roots-store/gkm-roots-certificate.c
+++ b/pkcs11/roots-store/gkm-roots-certificate.c
@@ -22,9 +22,9 @@
 #include "config.h"
 
 #include "gkm-roots-certificate.h"
+#include "gkm-roots-trust.h"
 
 #include "gkm/gkm-attributes.h"
-#include "gkm/gkm-certificate-trust.h"
 #include "gkm/gkm-manager.h"
 #include "gkm/gkm-module.h"
 #include "gkm/gkm-object.h"
@@ -35,13 +35,12 @@
 
 enum {
 	PROP_0,
-	PROP_PATH,
-	PROP_NETSCAPE_TRUST,
+	PROP_PATH
 };
 
 struct _GkmRootsCertificate {
 	GkmCertificate parent;
-	GkmCertificateTrust *trust;
+	GkmRootsTrust *trust;
 	gchar *path;
 };
 
@@ -97,9 +96,9 @@ gkm_roots_certificate_constructor (GType type, guint n_props, GObjectConstructPa
 	GkmRootsCertificate *self = GKM_ROOTS_CERTIFICATE (G_OBJECT_CLASS (gkm_roots_certificate_parent_class)->constructor(type, n_props, props));
 	g_return_val_if_fail (self, NULL);
 
-	self->trust = gkm_certificate_trust_new (gkm_object_get_module (GKM_OBJECT (self)),
-	                                         gkm_object_get_manager (GKM_OBJECT (self)),
-	                                         GKM_CERTIFICATE (self));
+	self->trust = gkm_roots_trust_new (gkm_object_get_module (GKM_OBJECT (self)),
+	                                   gkm_object_get_manager (GKM_OBJECT (self)),
+	                                   GKM_CERTIFICATE (self));
 
 	return G_OBJECT (self);
 }
@@ -131,9 +130,6 @@ gkm_roots_certificate_get_property (GObject *obj, guint prop_id, GValue *value,
 	case PROP_PATH:
 		g_value_set_string (value, gkm_roots_certificate_get_path (self));
 		break;
-	case PROP_NETSCAPE_TRUST:
-		g_value_set_object (value, gkm_roots_certificate_get_netscape_trust (self));
-		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -183,10 +179,6 @@ gkm_roots_certificate_class_init (GkmRootsCertificateClass *klass)
 	g_object_class_install_property (gobject_class, PROP_PATH,
 	           g_param_spec_string ("path", "Path", "Certificate origin path",
 	                                "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_class_install_property (gobject_class, PROP_NETSCAPE_TRUST,
-	           g_param_spec_object ("netscape-trust", "Netscape Trust", "Netscape trust object",
-	                                GKM_TYPE_CERTIFICATE_TRUST, G_PARAM_READABLE));
 }
 
 /* -----------------------------------------------------------------------------
@@ -206,11 +198,3 @@ gkm_roots_certificate_get_path (GkmRootsCertificate *self)
 	g_return_val_if_fail (GKM_IS_ROOTS_CERTIFICATE (self), "");
 	return self->path;
 }
-
-GkmCertificateTrust*
-gkm_roots_certificate_get_netscape_trust (GkmRootsCertificate *self)
-{
-	g_return_val_if_fail (GKM_IS_ROOTS_CERTIFICATE (self), NULL);
-	g_return_val_if_fail (GKM_IS_CERTIFICATE_TRUST (self->trust), NULL);
-	return self->trust;
-}
diff --git a/pkcs11/roots-store/gkm-roots-certificate.h b/pkcs11/roots-store/gkm-roots-certificate.h
index 8938425..9d61caf 100644
--- a/pkcs11/roots-store/gkm-roots-certificate.h
+++ b/pkcs11/roots-store/gkm-roots-certificate.h
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include "gkm/gkm-certificate.h"
+#include "gkm-roots-trust.h"
 
 #define GKM_TYPE_ROOTS_CERTIFICATE               (gkm_roots_certificate_get_type ())
 #define GKM_ROOTS_CERTIFICATE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_TYPE_ROOTS_CERTIFICATE, GkmRootsCertificate))
@@ -50,6 +51,4 @@ const gchar*          gkm_roots_certificate_get_unique             (GkmRootsCert
 
 const gchar*          gkm_roots_certificate_get_path               (GkmRootsCertificate *self);
 
-GkmCertificateTrust*  gkm_roots_certificate_get_netscape_trust     (GkmRootsCertificate *self);
-
 #endif /* __GKM_ROOTS_CERTIFICATE_H__ */
diff --git a/pkcs11/roots-store/gkm-roots-trust.c b/pkcs11/roots-store/gkm-roots-trust.c
new file mode 100644
index 0000000..eb52124
--- /dev/null
+++ b/pkcs11/roots-store/gkm-roots-trust.c
@@ -0,0 +1,411 @@
+/*
+ * gnome-trustring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2010 Collabora Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkm-roots-trust.h"
+
+#include "gkm/gkm-assertion.h"
+#include "gkm/gkm-attributes.h"
+#include "gkm/gkm-certificate.h"
+#include "gkm/gkm-data-der.h"
+#include "gkm/gkm-object.h"
+#include "gkm/gkm-oids.h"
+#include "gkm/gkm-util.h"
+
+#include "pkcs11/pkcs11i.h"
+#include "pkcs11/pkcs11n.h"
+
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_CERTIFICATE
+};
+
+struct _GkmRootsTrustPrivate {
+	GkmCertificate *certificate;
+	GList *assertions;
+};
+
+G_DEFINE_TYPE (GkmRootsTrust, gkm_roots_trust, GKM_TYPE_TRUST);
+
+static GQuark OID_KEY_USAGE;
+static GQuark OID_ENHANCED_USAGE;
+
+/*
+ * When a certificate doesn't explicitly supply the purposes it's allowed
+ * to use, and gives carte blanche then we use the following list.
+ */
+
+const char *OID_KNOWN_PURPOSES[] = {
+	GKM_OID_EXTUSAGE_SERVER_AUTH,
+	GKM_OID_EXTUSAGE_CLIENT_AUTH,
+	GKM_OID_EXTUSAGE_CODE_SIGNING,
+	GKM_OID_EXTUSAGE_EMAIL,
+	GKM_OID_EXTUSAGE_IPSEC_ENDPOINT,
+	GKM_OID_EXTUSAGE_IPSEC_TUNNEL,
+	GKM_OID_EXTUSAGE_IPSEC_USER,
+	GKM_OID_EXTUSAGE_TIME_STAMPING,
+	NULL
+};
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+init_quarks (void)
+{
+	static volatile gsize quarks_inited = 0;
+
+	if (g_once_init_enter (&quarks_inited)) {
+		#define QUARK(name, value) \
+			name = g_quark_from_static_string(value)
+
+		QUARK (OID_ENHANCED_USAGE, "2.5.29.37");
+		QUARK (OID_KEY_USAGE, "2.5.29.15");
+
+		#undef QUARK
+
+		g_once_init_leave (&quarks_inited, 1);
+	}
+}
+
+static CK_RV
+hash_certificate (GkmRootsTrust *self, int algo, CK_ATTRIBUTE_PTR result)
+{
+	guchar *hash;
+	gsize n_hash;
+	CK_RV rv;
+
+	g_assert (GKM_ROOTS_IS_TRUST (self));
+
+	g_return_val_if_fail (self->pv->certificate, CKR_GENERAL_ERROR);
+
+	hash = gkm_certificate_hash (self->pv->certificate, algo, &n_hash);
+	g_return_val_if_fail (hash, CKR_GENERAL_ERROR);
+
+	rv = gkm_attribute_set_data (result, hash, n_hash);
+	g_free (hash);
+
+	return rv;
+}
+
+static GQuark*
+lookup_extended_usages (GkmRootsTrust *self)
+{
+	gconstpointer extension;
+	gsize n_extension;
+	GQuark *usages = NULL;
+	GkmDataResult res;
+
+	extension = gkm_certificate_get_extension (self->pv->certificate,
+	                                           OID_ENHANCED_USAGE,
+	                                           &n_extension, NULL);
+
+	if (!extension)
+		return NULL;
+
+	/* Returns null terminated set of OID quarks */
+	res = gkm_data_der_read_enhanced_usage (extension, n_extension, &usages);
+
+	/* Failure: An empty set means nothing is trusted */
+	if (res != GKM_DATA_SUCCESS) {
+		g_message ("couldn't parse extended usage info in certificate");
+		usages = g_new0 (GQuark, 1);
+	}
+
+	return usages;
+}
+
+static gboolean
+is_certificate_authority (GkmCertificate *cert)
+{
+	gulong nval;
+
+	if (!gkm_object_get_attribute_ulong (GKM_OBJECT (cert),
+	                                     NULL, CKA_CERTIFICATE_CATEGORY, &nval))
+		nval = 0;
+
+	/* 2 is a certificate authority in PKCS#11 */
+	return (nval == 2) ? TRUE : FALSE;
+}
+
+static void
+build_linked_assertion (GkmRootsTrust *self, GkmTrustLevel level, const gchar *purpose)
+{
+	GkmAssertion *assertion;
+	gulong type = 0;
+
+	/* For now only have logic to create assertions early */
+	g_return_if_fail (!gkm_object_is_exposed (GKM_OBJECT (self)));
+
+	switch (level) {
+	case GKM_TRUST_UNKNOWN:
+		return;
+	case GKM_TRUST_TRUSTED:
+		type = CKT_G_CERTIFICATE_TRUST_EXCEPTION;
+		break;
+	case GKM_TRUST_UNTRUSTED:
+		type = CKT_G_CERTIFICATE_UNTRUSTED;
+		break;
+	case GKM_TRUST_ANCHOR:
+		type = CKT_G_CERTIFICATE_TRUST_ANCHOR;
+		break;
+	default:
+		g_assert_not_reached ();
+		return;
+	};
+
+	assertion = gkm_assertion_new (GKM_TRUST (self), type, purpose, NULL);
+	self->pv->assertions = g_list_prepend (self->pv->assertions, assertion);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gkm_roots_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+	GkmRootsTrust *self = GKM_ROOTS_TRUST (base);
+
+	switch (attr->type)
+	{
+	case CKA_SUBJECT:
+	case CKA_SERIAL_NUMBER:
+	case CKA_ISSUER:
+	case CKA_VALUE:
+		g_return_val_if_fail (self->pv->certificate, CKR_GENERAL_ERROR);
+		return gkm_object_get_attribute (GKM_OBJECT (self->pv->certificate), session, attr);
+
+	case CKA_CERT_MD5_HASH:
+		return hash_certificate (self, GCRY_MD_MD5, attr);
+	case CKA_CERT_SHA1_HASH:
+		return hash_certificate (self, GCRY_MD_SHA1, attr);
+
+	default:
+		break;
+	};
+
+	return GKM_OBJECT_CLASS (gkm_roots_trust_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gkm_roots_trust_expose_object (GkmObject *base, gboolean expose)
+{
+	GList *l;
+	GKM_OBJECT_CLASS (gkm_roots_trust_parent_class)->expose_object (base, expose);
+	for (l = GKM_ROOTS_TRUST (base)->pv->assertions; l; l = g_list_next (l))
+		gkm_object_expose (l->data, expose);
+}
+
+static GkmTrustLevel
+gkm_roots_trust_get_trust_level (GkmTrust *base, const gchar *purpose)
+{
+	GkmRootsTrust *self;
+	GkmTrustLevel result;
+	GQuark *usage, *usages;
+	GQuark oid;
+
+	self = GKM_ROOTS_TRUST (base);
+
+	/*
+	 * For root certificates we just believe whatever is in the
+	 * certificate enhanced usage extension.
+	 */
+
+	usages = lookup_extended_usages (self);
+
+	/* No enhanced usage noted, any are allowed */
+	if (!usages) {
+		result = GKM_TRUST_TRUSTED;
+
+	} else {
+		result = GKM_TRUST_UNTRUSTED;
+		oid = g_quark_try_string (purpose);
+		for (usage = usages; *usage; ++usage) {
+			if (*usage == oid) {
+				result = GKM_TRUST_TRUSTED;
+				break;
+			}
+		}
+	}
+
+	g_free (usages);
+
+	/* See if we can delegate the trust (ie: CA) */
+	if (result == GKM_TRUST_TRUSTED && is_certificate_authority (self->pv->certificate))
+		result = GKM_TRUST_ANCHOR;
+
+	return result;
+}
+
+static void
+gkm_roots_trust_init (GkmRootsTrust *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKM_ROOTS_TYPE_TRUST, GkmRootsTrustPrivate);
+}
+
+static GObject*
+gkm_roots_trust_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+	GkmRootsTrust *self;
+	GQuark *usages, *u;
+	const gchar **p;
+	GkmTrustLevel level;
+
+	self = GKM_ROOTS_TRUST (G_OBJECT_CLASS (gkm_roots_trust_parent_class)->constructor (type, n_props, props));
+	g_return_val_if_fail (self->pv->certificate, NULL);
+
+	usages = lookup_extended_usages (self);
+
+	if (is_certificate_authority (self->pv->certificate))
+		level = GKM_TRUST_TRUSTED;
+	else
+		level = GKM_TRUST_ANCHOR;
+
+	/* Build assertions for all the listed usages */
+	if (usages) {
+		for (u = usages; *u; ++u)
+			build_linked_assertion (self, level, g_quark_to_string (*u));
+
+	/* Build assertions for all the known default purposes */
+	} else {
+		for (p = OID_KNOWN_PURPOSES; *p; ++p)
+			build_linked_assertion (self, level, *p);
+	}
+
+	return G_OBJECT (self);
+}
+
+static void
+gkm_roots_trust_dispose (GObject *obj)
+{
+	GkmRootsTrust *self = GKM_ROOTS_TRUST (obj);
+	GList *l;
+
+	for (l = self->pv->assertions; l; l = g_list_next (l)) {
+		g_object_run_dispose (G_OBJECT (l->data));
+		g_object_unref (l->data);
+	}
+
+	g_list_free (self->pv->assertions);
+	self->pv->assertions = NULL;
+
+	G_OBJECT_CLASS (gkm_roots_trust_parent_class)->dispose (obj);
+}
+
+static void
+gkm_roots_trust_finalize (GObject *obj)
+{
+	GkmRootsTrust *self = GKM_ROOTS_TRUST (obj);
+
+	if (self->pv->certificate)
+		g_object_remove_weak_pointer (G_OBJECT (self->pv->certificate), (gpointer*)&(self->pv->certificate));
+	self->pv->certificate = NULL;
+
+	g_assert (!self->pv->assertions);
+
+	G_OBJECT_CLASS (gkm_roots_trust_parent_class)->finalize (obj);
+}
+
+static void
+gkm_roots_trust_set_property (GObject *obj, guint prop_id, const GValue *value,
+                           GParamSpec *pspec)
+{
+	GkmRootsTrust *self = GKM_ROOTS_TRUST (obj);
+
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		g_return_if_fail (!self->pv->certificate);
+		self->pv->certificate = g_value_get_object (value);
+		g_return_if_fail (self->pv->certificate);
+		g_object_add_weak_pointer (G_OBJECT (self->pv->certificate), (gpointer*)&(self->pv->certificate));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gkm_roots_trust_get_property (GObject *obj, guint prop_id, GValue *value,
+                           GParamSpec *pspec)
+{
+	GkmRootsTrust *self = GKM_ROOTS_TRUST (obj);
+
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		g_value_set_object (value, gkm_roots_trust_get_certificate (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gkm_roots_trust_class_init (GkmRootsTrustClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
+	GkmTrustClass *trust_class = GKM_TRUST_CLASS (klass);
+
+	gobject_class->constructor = gkm_roots_trust_constructor;
+	gobject_class->dispose = gkm_roots_trust_dispose;
+	gobject_class->finalize = gkm_roots_trust_finalize;
+	gobject_class->set_property = gkm_roots_trust_set_property;
+	gobject_class->get_property = gkm_roots_trust_get_property;
+
+	gkm_class->get_attribute = gkm_roots_trust_get_attribute;
+	gkm_class->expose_object = gkm_roots_trust_expose_object;
+
+	trust_class->get_trust_level = gkm_roots_trust_get_trust_level;
+
+	g_type_class_add_private (klass, sizeof (GkmRootsTrustPrivate));
+
+	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
+	           g_param_spec_object ("certificate", "Certificate", "Certificate this trust belongs to",
+	                                GKM_TYPE_CERTIFICATE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	init_quarks ();
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GkmRootsTrust*
+gkm_roots_trust_new (GkmModule *module, GkmManager *manager, GkmCertificate *cert)
+{
+	return g_object_new (GKM_ROOTS_TYPE_TRUST, "module", module,
+	                     "manager", manager, "certificate", cert, NULL);
+}
+
+GkmCertificate*
+gkm_roots_trust_get_certificate (GkmRootsTrust *self)
+{
+	g_return_val_if_fail (GKM_ROOTS_IS_TRUST (self), NULL);
+	g_return_val_if_fail (self->pv->certificate, NULL);
+	return self->pv->certificate;
+}
diff --git a/pkcs11/roots-store/gkm-roots-trust.h b/pkcs11/roots-store/gkm-roots-trust.h
new file mode 100644
index 0000000..def17aa
--- /dev/null
+++ b/pkcs11/roots-store/gkm-roots-trust.h
@@ -0,0 +1,60 @@
+/*
+ * gnome-trustring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2010 Collabora Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKM_ROOTS_TRUST_H__
+#define __GKM_ROOTS_TRUST_H__
+
+#include <glib-object.h>
+
+#include "gkm/gkm-trust.h"
+#include "gkm/gkm-object.h"
+#include "gkm/gkm-types.h"
+
+#define GKM_ROOTS_TYPE_TRUST               (gkm_roots_trust_get_type ())
+#define GKM_ROOTS_TRUST(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_ROOTS_TYPE_TRUST, GkmRootsTrust))
+#define GKM_ROOTS_TRUST_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_ROOTS_TYPE_TRUST, GkmRootsTrustClass))
+#define GKM_ROOTS_IS_TRUST(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_ROOTS_TYPE_TRUST))
+#define GKM_ROOTS_IS_TRUST_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_ROOTS_TYPE_TRUST))
+#define GKM_ROOTS_TRUST_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_ROOTS_TYPE_TRUST, GkmRootsTrustClass))
+
+typedef struct _GkmRootsTrust GkmRootsTrust;
+typedef struct _GkmRootsTrustClass GkmRootsTrustClass;
+typedef struct _GkmRootsTrustPrivate GkmRootsTrustPrivate;
+
+struct _GkmRootsTrust {
+	GkmTrust parent;
+	GkmRootsTrustPrivate *pv;
+};
+
+struct _GkmRootsTrustClass {
+	GkmTrustClass parent_class;
+};
+
+GType                 gkm_roots_trust_get_type               (void);
+
+GkmRootsTrust*        gkm_roots_trust_new                    (GkmModule *module,
+                                                              GkmManager *manager,
+                                                              GkmCertificate *cert);
+
+GkmCertificate*       gkm_roots_trust_get_certificate        (GkmRootsTrust *self);
+
+#endif /* __GKM_ROOTS_TRUST_H__ */
diff --git a/pkcs11/xdg-store/Makefile.am b/pkcs11/xdg-store/Makefile.am
index a0bc901..931613a 100644
--- a/pkcs11/xdg-store/Makefile.am
+++ b/pkcs11/xdg-store/Makefile.am
@@ -18,6 +18,7 @@ BUILT_SOURCES = \
 
 libgkm_xdg_store_la_SOURCES = \
 	gkm-xdg-store.h \
+	gkm-xdg-assertion.c gkm-xdg-assertion.h \
 	gkm-xdg-module.c gkm-xdg-module.h \
 	gkm-xdg-trust.c gkm-xdg-trust.h \
 	$(BUILT_SOURCES)
diff --git a/pkcs11/xdg-store/asn1-def-xdg.c b/pkcs11/xdg-store/asn1-def-xdg.c
index 0d1edd9..9e9dfee 100644
--- a/pkcs11/xdg-store/asn1-def-xdg.c
+++ b/pkcs11/xdg-store/asn1-def-xdg.c
@@ -7,31 +7,36 @@
 const ASN1_ARRAY_TYPE xdg_asn1_tab[] = {
   { "XDG", 536872976, NULL },
   { NULL, 1073741836, NULL },
-  { "TrustDigest", 1610612741, NULL },
-  { "algorithm", 1073741836, NULL },
-  { "digest", 7, NULL },
-  { "TrustDigests", 1610612747, NULL },
-  { NULL, 2, "TrustDigest"},
   { "TrustLevel", 1610874901, NULL },
-  { "trustUnknown", 1073741825, "0"},
+  { "unknown", 1073741825, "0"},
   { "untrusted", 1073741825, "1"},
-  { "mustVerify", 1073741825, "2"},
   { "trusted", 1073741825, "3"},
-  { "trustedDelegator", 1, "4"},
-  { "TrustPair", 1610612741, NULL },
+  { "trustedAnchor", 1, "4"},
+  { "TrustAssertion", 1610612741, NULL },
   { "purpose", 1073741836, NULL },
-  { "level", 2, "TrustLevel"},
-  { "TrustPairs", 1610612747, NULL },
-  { NULL, 2, "TrustPair"},
+  { "level", 1073741826, "TrustLevel"},
+  { "with", 1073741831, NULL },
+  { "additions", 536870923, NULL },
+  { NULL, 13, NULL },
+  { "TrustAssertions", 1610612747, NULL },
+  { NULL, 2, "TrustAssertion"},
   { "CertReference", 1610612741, NULL },
   { "serialNumber", 1073741827, NULL },
   { "issuer", 1073741837, NULL },
   { "subject", 1073758221, NULL },
-  { "digests", 16386, "TrustDigests"},
+  { "additions", 536870923, NULL },
+  { NULL, 13, NULL },
   { "TrustReference", 1610612754, NULL },
-  { "certReference", 2, "CertReference"},
+  { "certReference", 1610620930, "CertReference"},
+  { NULL, 2056, "0"},
+  { "certComplete", 1610620941, NULL },
+  { NULL, 2056, "1"},
+  { "additions", 536879117, NULL },
+  { NULL, 2056, "2"},
   { "trust-1", 536870917, NULL },
   { "reference", 1073741826, "TrustReference"},
-  { "trusts", 2, "TrustPairs"},
+  { "assertions", 1073741826, "TrustAssertions"},
+  { "additions", 536870923, NULL },
+  { NULL, 13, NULL },
   { NULL, 0, NULL }
 };
diff --git a/pkcs11/xdg-store/gkm-xdg-assertion.c b/pkcs11/xdg-store/gkm-xdg-assertion.c
new file mode 100644
index 0000000..0c88613
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-assertion.c
@@ -0,0 +1,252 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkm-xdg-assertion.h"
+#include "gkm-xdg-trust.h"
+
+#include "gkm/gkm-attributes.h"
+#include "gkm/gkm-object.h"
+#include "gkm/gkm-session.h"
+#include "gkm/gkm-transaction.h"
+#include "gkm/gkm-trust.h"
+#include "gkm/gkm-util.h"
+
+#include "pkcs11/pkcs11i.h"
+#include "pkcs11/pkcs11n.h"
+
+#include <glib/gi18n.h>
+
+struct _GkmXdgAssertionPrivate {
+
+};
+
+G_DEFINE_TYPE (GkmXdgAssertion, gkm_xdg_assertion, GKM_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * QUARKS
+ */
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static GkmTrust*
+lookup_or_create_trust_object (GkmSession *session, GkmManager *manager,
+                               GkmTransaction *transaction, CK_ASSERTION_TYPE type,
+                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gboolean *created)
+{
+	CK_ATTRIBUTE_PTR serial, issuer, value;
+	CK_ATTRIBUTE lookups[3];
+	CK_OBJECT_CLASS klass;
+	CK_ULONG n_lookups;
+	GList *objects;
+	GkmTrust *trust;
+	GkmModule *module;
+
+	klass = CKO_NETSCAPE_TRUST;
+	lookups[0].type = CKA_CLASS;
+	lookups[0].pValue = &klass;
+	lookups[0].ulValueLen = sizeof (klass);
+
+	switch (type) {
+	case CKT_G_CERTIFICATE_TRUST_ANCHOR:
+	case CKT_G_CERTIFICATE_TRUST_EXCEPTION:
+		value = gkm_attributes_find (attrs, n_attrs, CKA_G_CERTIFICATE_VALUE);
+		if (!value) {
+			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+			return NULL;
+		}
+
+		/* Attributes used for looking up trust object */
+		memcpy (lookups + 1, value, sizeof (value));
+		n_lookups = 2;
+		break;
+
+	case CKT_G_CERTIFICATE_UNTRUSTED:
+		serial = gkm_attributes_find (attrs, n_attrs, CKA_SERIAL_NUMBER);
+		issuer = gkm_attributes_find (attrs, n_attrs, CKA_ISSUER);
+		if (!serial || !issuer) {
+			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+			return NULL;
+		}
+
+		/* Attributes used for looking up trust object */
+		memcpy (lookups + 1, issuer, sizeof (issuer));
+		memcpy (lookups + 2, issuer, sizeof (serial));
+		n_lookups = 2;
+		break;
+
+	default:
+		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+		return NULL;
+	};
+
+	objects = gkm_manager_find_by_attributes (manager, session, lookups, n_lookups);
+	module = gkm_session_get_module (session);
+
+	/* Found a matching trust object for this assertion */
+	if (objects) {
+		g_return_val_if_fail (GKM_IS_TRUST (objects->data), NULL);
+		trust = GKM_TRUST (objects->data);
+		g_list_free (objects);
+
+	/* Create a trust object for this assertion */
+	} else {
+		trust = gkm_xdg_trust_create_for_assertion (module, manager, transaction,
+		                                            lookups, n_lookups);
+	}
+
+	gkm_attributes_consume (attrs, n_attrs, CKA_G_CERTIFICATE_VALUE,
+	                        CKA_ISSUER, CKA_SERIAL_NUMBER, G_MAXULONG);
+	gkm_attributes_consume (lookups, n_lookups, CKA_G_CERTIFICATE_VALUE,
+	                        CKA_ISSUER, CKA_SERIAL_NUMBER, G_MAXULONG);
+
+	if (!gkm_transaction_get_failed (transaction)) {
+		gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (trust),
+		                                      TRUE, lookups, n_lookups);
+	}
+
+	return trust;
+}
+
+static GkmObject*
+factory_create_assertion (GkmSession *session, GkmTransaction *transaction,
+                          CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	GkmAssertion *assertion;
+	CK_ASSERTION_TYPE type;
+	GkmManager *manager;
+	gboolean created = FALSE;
+	GkmTrust *trust;
+	gchar *purpose;
+
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
+
+	if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_ASSERTION_TYPE, &type)) {
+		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
+
+	if (!gkm_attributes_find_string (attrs, n_attrs, CKA_G_PURPOSE, &purpose)) {
+		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
+
+	/* Try to find or create an appropriate trust object for this assertion */
+	manager = gkm_manager_for_template (attrs, n_attrs, session);
+	trust = lookup_or_create_trust_object (session, manager, transaction,
+	                                       type, attrs, n_attrs, &created);
+
+	/* Creating the trust object failed */
+	if (trust == NULL) {
+		g_return_val_if_fail (gkm_transaction_get_failed (transaction), NULL);
+		g_free (purpose);
+		return NULL;
+	}
+
+	assertion = g_object_new (GKM_XDG_TYPE_ASSERTION, "trust", trust,
+	                          "type", type, "purpose", purpose, NULL);
+
+	gkm_attributes_consume (attrs, n_attrs, CKA_G_ASSERTION_TYPE, CKA_G_PURPOSE, G_MAXULONG);
+	gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (assertion),
+	                                      TRUE, attrs, n_attrs);
+
+	return GKM_OBJECT (trust);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gkm_xdg_assertion_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+#if 0
+	GkmXdgAssertion *self = GKM_XDG_ASSERTION (base);
+
+	switch (attr->type)
+	{
+	case CKA_G
+	/* Various trust flags */
+	case CKA_G_TRUST_LEVEL:
+		xxxx;
+	case CKA_G_TRUST_PURPOSE:
+		xxxx;
+
+	default:
+		break;
+	};
+
+#endif
+	return GKM_OBJECT_CLASS (gkm_xdg_assertion_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gkm_xdg_assertion_init (GkmXdgAssertion *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKM_XDG_TYPE_ASSERTION, GkmXdgAssertionPrivate);
+}
+
+static void
+gkm_xdg_assertion_finalize (GObject *obj)
+{
+#if 0
+	GkmXdgAssertion *self = GKM_XDG_ASSERTION (obj);
+#endif
+	G_OBJECT_CLASS (gkm_xdg_assertion_parent_class)->finalize (obj);
+}
+
+static void
+gkm_xdg_assertion_class_init (GkmXdgAssertionClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
+
+	gobject_class->finalize = gkm_xdg_assertion_finalize;
+	gkm_class->get_attribute = gkm_xdg_assertion_get_attribute;
+
+	g_type_class_add_private (klass, sizeof (GkmXdgAssertionPrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+
+GkmFactory*
+gkm_xdg_assertion_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_G_TRUST_ASSERTION;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+	};
+
+	static GkmFactory factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		factory_create_assertion
+	};
+
+	return &factory;
+}
diff --git a/pkcs11/xdg-store/gkm-xdg-assertion.h b/pkcs11/xdg-store/gkm-xdg-assertion.h
new file mode 100644
index 0000000..75bc073
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-assertion.h
@@ -0,0 +1,55 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ * Copyright (C) 2010 Collabora Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKM_XDG_ASSERTION_H__
+#define __GKM_XDG_ASSERTION_H__
+
+#include <glib-object.h>
+
+#include "gkm/gkm-object.h"
+
+#define GKM_XDG_FACTORY_ASSERTION            (gkm_xdg_assertion_get_factory ())
+#define GKM_XDG_TYPE_ASSERTION               (gkm_xdg_assertion_get_type ())
+#define GKM_XDG_ASSERTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_XDG_TYPE_ASSERTION, GkmXdgAssertion))
+#define GKM_XDG_ASSERTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_XDG_TYPE_ASSERTION, GkmXdgAssertionClass))
+#define GKM_XDG_IS_ASSERTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_XDG_TYPE_ASSERTION))
+#define GKM_XDG_IS_ASSERTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_XDG_TYPE_ASSERTION))
+#define GKM_XDG_ASSERTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_XDG_TYPE_ASSERTION, GkmXdgAssertionClass))
+
+typedef struct _GkmXdgAssertion GkmXdgAssertion;
+typedef struct _GkmXdgAssertionClass GkmXdgAssertionClass;
+typedef struct _GkmXdgAssertionPrivate GkmXdgAssertionPrivate;
+
+struct _GkmXdgAssertion {
+	GkmObject parent;
+	GkmXdgAssertionPrivate *pv;
+};
+
+struct _GkmXdgAssertionClass {
+	GkmObjectClass parent_class;
+};
+
+GType                 gkm_xdg_assertion_get_type               (void);
+
+GkmFactory*           gkm_xdg_assertion_get_factory            (void);
+
+#endif /* __GKM_XDG_ASSERTION_H__ */
diff --git a/pkcs11/xdg-store/gkm-xdg-module.c b/pkcs11/xdg-store/gkm-xdg-module.c
index 64bdcf7..92f9fbc 100644
--- a/pkcs11/xdg-store/gkm-xdg-module.c
+++ b/pkcs11/xdg-store/gkm-xdg-module.c
@@ -23,7 +23,7 @@
 
 #include "gkm-xdg-module.h"
 #include "gkm-xdg-store.h"
-#include "gkm-xdg-trust.h"
+#include "gkm-xdg-assertion.h"
 
 #include "egg/egg-asn1x.h"
 #include "egg/egg-asn1-defs.h"
@@ -31,6 +31,7 @@
 #include "egg/egg-error.h"
 #include "egg/egg-hex.h"
 
+#include "gkm/gkm-assertion.h"
 #include "gkm/gkm-file-tracker.h"
 #include "gkm/gkm-serializable.h"
 #include "gkm/gkm-transaction.h"
@@ -105,7 +106,7 @@ type_from_path (const gchar *path)
 		return 0;
 
 	if (g_str_equal (ext, ".trust"))
-		return GKM_XDG_TYPE_TRUST;
+		return GKM_XDG_TYPE_ASSERTION;
 
 #if 0
 	else if (strcmp (extension, ".pkcs8") == 0)
@@ -310,12 +311,19 @@ gkm_xdg_module_real_add_token_object (GkmModule *module, GkmTransaction *transac
                                       GkmObject *object)
 {
 	GkmXdgModule *self;
+	GkmTrust *trust;
 	gchar *basename;
 	gchar *actual;
 	gchar *filename;
 
 	self = GKM_XDG_MODULE (module);
 
+	/* Always serialize the trust object for each assertion */
+	if (GKM_XDG_IS_ASSERTION (object)) {
+		trust = gkm_assertion_get_trust_object (GKM_ASSERTION (object));
+		object = GKM_OBJECT (trust);
+	}
+
 	/* Double check that the object is in fact serializable */
 	if (!GKM_IS_SERIALIZABLE (object)) {
 		g_message ("can't store object of type '%s' on token", G_OBJECT_TYPE_NAME (object));
@@ -344,10 +352,17 @@ gkm_xdg_module_real_store_token_object (GkmModule *module, GkmTransaction *trans
                                         GkmObject *object)
 {
 	GkmXdgModule *self = GKM_XDG_MODULE (module);
+	GkmTrust *trust;
 	const gchar *filename;
 	gpointer data;
 	gsize n_data;
 
+	/* Always serialize the trust object for each assertion */
+	if (GKM_XDG_IS_ASSERTION (object)) {
+		trust = gkm_assertion_get_trust_object (GKM_ASSERTION (object));
+		object = GKM_OBJECT (trust);
+	}
+
 	/* Double check that the object is in fact serializable */
 	if (!GKM_IS_SERIALIZABLE (object)) {
 		g_message ("can't store object of type '%s' on token", G_OBJECT_TYPE_NAME (object));
@@ -376,6 +391,9 @@ gkm_xdg_module_real_remove_token_object (GkmModule *module, GkmTransaction *tran
 	GkmXdgModule *self = GKM_XDG_MODULE (module);
 	const gchar *filename;
 
+	/* XXXX; need to implement for assertions */
+	g_assert_not_reached ();
+
 	filename = lookup_filename_for_object (object);
 	g_return_if_fail (filename != NULL);
 	g_return_if_fail (g_hash_table_lookup (self->objects_by_path, filename) == object);
@@ -409,8 +427,8 @@ gkm_xdg_module_init (GkmXdgModule *self)
 	/* Our default token info, updated as module runs */
 	memcpy (&self->token_info, &user_module_token_info, sizeof (CK_TOKEN_INFO));
 
-	/* For creating stored keys */
-	gkm_module_register_factory (GKM_MODULE (self), GKM_XDG_FACTORY_TRUST);
+	/* For creating stored objects */
+	gkm_module_register_factory (GKM_MODULE (self), GKM_XDG_FACTORY_ASSERTION);
 }
 
 static void
diff --git a/pkcs11/xdg-store/gkm-xdg-trust-netscape.c b/pkcs11/xdg-store/gkm-xdg-trust-netscape.c
new file mode 100644
index 0000000..0a41a09
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-trust-netscape.c
@@ -0,0 +1,314 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkm-xdg-trust-netscape.h"
+
+#include "egg/egg-asn1x.h"
+
+#include "gkm/gkm-attributes.h"
+#include "gkm/gkm-object.h"
+#include "gkm/gkm-serializable.h"
+#include "gkm/gkm-session.h"
+#include "gkm/gkm-transaction.h"
+#include "gkm/gkm-util.h"
+
+#include "pkcs11/pkcs11g.h"
+#include "pkcs11/pkcs11n.h"
+
+#include <libtasn1.h>
+
+#include <glib/gi18n.h>
+
+struct _GkmXdgTrustNetscapePrivate {
+	GHashTable *assertions;
+};
+
+G_DEFINE_TYPE (GkmXdgTrustNetscape, gkm_xdg_trust_netscape, GKM_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static GkmXdgTrustNetscape*
+lookup_or_create_matching_netscape_trust (GkmXdgTrust *assertion)
+{
+	CK_OBJECT_CLASS klass = CKO_NETSCAPE_TRUST;
+	GkmXdgTrustNetscape *netscape;
+	GkmManager *manager;
+	GkmModule *module;
+	CK_ATTRIBUTE attrs[5];
+	GList *objects;
+
+	attrs[0].type = CKA_CLASS;
+	attrs[0].pValue = &klass;
+	attrs[0].ulValueLen = sizeof (klass);
+
+	switch (gkm_xdg_trust_get_assertion_type (assertion)) {
+	case GKM_XDG_TRUST_ROOT:
+		data = gkm_xdg_trust_get_hash (assertion, G_CHECKSUM_SHA1, &n_data);
+		g_return_val_if_fail (data, NULL);
+		attrs[1].type = CKA_CERT_SHA1_HASH;
+		attrs[1].pValue = data;
+		attrs[1].ulValueLen = n_data;
+		n_attrs = 2;
+		break;
+	case GKM_XDG_TRUST_EXCEPTION:
+		data = gkm_xdg_trust_get_serial (assertion, &n_data);
+		g_return_val_if_fail (data, NULL);
+		attrs[1].type = CKA_SERIAL_NUMBER;
+		attrs[1].pValue = data;
+		attrs[1].ulValueLen = n_data;
+		data = gkm_xdg_trust_get_issuer (assertion, &n_data);
+		g_return_val_if_fail (data, NULL);
+		attrs[2].type = CKA_ISSUER;
+		attrs[2].pValue = data;
+		attrs[2].ulValueLen = n_data;
+		n_attrs = 3;
+		break;
+	default:
+		g_return_val_if_reached (NULL);
+	};
+
+	manager = gkm_object_get_manager (GKM_OBJECT (assertion));
+	objects = gkm_manager_find_by_attributes (manager, NULL, attrs, n_attrs);
+
+	if (objects) {
+		g_assert (objects->data);
+		netscape = GKM_XDG_TRUST_NETSCAPE (objects->data);
+		g_list_free (objects->data);
+	} else {
+		trust = g_object_new (GKM_XDG_TYPE_TRUST_NETSCAPE,
+		                      "module", gkm_object_get_module (assertion),
+		                      "manager", manager,
+		                      NULL);
+		gkm_object_expose (GKM_OBJECT (trust), TRUE);
+
+#if XXXX
+		/* Certificate reference values */
+		case CKA_SUBJECT:
+			return trust_get_der (self, "subject", attr);
+		case CKA_SERIAL_NUMBER:
+			return trust_get_integer (self, "serialNumber", attr);
+		case CKA_ISSUER:
+			return trust_get_der (self, "issuer", attr);
+
+		/* Certificate hash values */
+		case CKA_CERT_MD5_HASH:
+			return trust_get_hash (self, OID_HASH_MD5, attr);
+		case CKA_CERT_SHA1_HASH:
+			return trust_get_hash (self, OID_HASH_SHA1, attr);
+#endif
+
+	}
+
+	xxxx ownership xxxx;
+
+	return trust;
+}
+
+static CK_RV
+lookup_certificate_hash (GkmXdgTrustNetscape *self, CK_ATTRIBUTE_PTR attr, GChecksumType type)
+{
+	GkmXdgAssertion *assertion;
+	GChecksum *checksum;
+	gpointer value, hash;
+	gconstpointer data;
+	gsize n_data, n_hash;
+	CK_RV rv;
+
+	if (self->pv->assertion_type != CKT_G_CERTIFICATE_ROOT)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	/* Find the first assertion */
+	g_hash_table_iter_init (&iter, self->pv->assertions);
+	if (!g_hash_table_iter_next (&iter, NULL, &value))
+		g_assert_not_reached ();
+	assertion = GKM_XDG_ASSERTION (value);
+
+	g_assert (gkm_xdg_assertion_get_assertion_type (assertion) == CKT_G_CERTIFICATE_ROOT);
+	data = gkm_xdg_assertion_get_certificate_value (assertion, &n_data);
+	g_return_val_if_fail (data, CKR_GENERAL_ERROR);
+
+	checksum = g_checksum_new (type);
+	g_checksum_update (checksum, data, n_data);
+	n_hash = g_checksum_type_get_length (type);
+	hash = g_malloc (n_hash);
+	g_checksum_get_digest (checksum, hash, &n_hash);
+	g_checksum_free (checksum);
+
+	rv = gkm_attribute_set_data (attr, hash, n_hash);
+	g_free (hash);
+
+	return rv;
+}
+
+static CK_RV
+lookup_assertion_attr (GkmXdgTrustNetscape *self, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+	GHashTableIter iter;
+	gpointer value;
+
+	/* Find the  first assertion, any will do */
+	g_hash_table_iter_init (&iter, self->pv->assertions);
+	if (!g_hash_table_iter_next (&iter, NULL, &value))
+		g_assert_not_reached ();
+
+	return gkm_object_get_attribute (GKM_OBJECT (value), session, attr);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gkm_xdg_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+	GkmXdgTrustNetscape *self = GKM_XDG_TRUST (base);
+	GkmXdgAssertion *assertion;
+	CK_ULONG value;
+
+	/* Attributes like subject, issuer, cert hashes */
+	for (i = 0; i < self->pv->n_attrs; ++i) {
+		if (self->pv->attrs[i].type == attr->type) {
+			gkm_attribute_set_data (attr, self->pv->attrs[i].pValue,
+			                        self->pv->attrs[i].ulValueLen);
+			return;
+		}
+	}
+
+	/* Look for overrides of the default flags and restrictions below */
+	assertion = g_hash_table_lookup (self->pv->assertions, &(attr->type));
+	if (assertion) {
+		level = gkm_xdg_assertion_get_level (assertion);
+		return gkm_attribute_set_ulong (attr, level_to_netscape_trust (level));
+	}
+
+	switch (attr->type)
+	{
+	case CKA_PRIVATE:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+	case CKA_TRUST_STEP_UP_APPROVED:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+	case CKA_CLASS:
+		return gkm_attribute_set_ulong (attr, CKO_NETSCAPE_TRUST);
+	case CKA_MODIFIABLE:
+		return gkm_attribute_set_bool (attr, CK_FALSE);
+
+	/* Key restrictions */
+	case CKA_TRUST_DIGITAL_SIGNATURE:
+	case CKA_TRUST_NON_REPUDIATION:
+	case CKA_TRUST_KEY_ENCIPHERMENT:
+	case CKA_TRUST_DATA_ENCIPHERMENT:
+	case CKA_TRUST_KEY_AGREEMENT:
+	case CKA_TRUST_KEY_CERT_SIGN:
+	case CKA_TRUST_CRL_SIGN:
+		return gkm_attribute_set_ulong (attr, CKT_NETSCAPE_TRUST_UNKNOWN);
+
+	/* Various trust flags */
+	case CKA_TRUST_SERVER_AUTH:
+	case CKA_TRUST_CLIENT_AUTH:
+	case CKA_TRUST_CODE_SIGNING:
+	case CKA_TRUST_EMAIL_PROTECTION:
+	case CKA_TRUST_IPSEC_END_SYSTEM:
+	case CKA_TRUST_IPSEC_TUNNEL:
+	case CKA_TRUST_IPSEC_USER:
+	case CKA_TRUST_TIME_STAMPING:
+		return gkm_attribute_set_ulong (attr, CKT_NETSCAPE_TRUST_UNKNOWN);
+
+	case CKA_CERT_MD5_HASH:
+		return lookup_certificate_hash (self, attr, G_CHECKSUM_MD5);
+	case CKA_CERT_SHA1_HASH:
+		return lookup_certificate_hash (self, attr, G_CHECKSUM_SHA1);
+
+	case CKA_LABEL:
+	case CKA_SUBJECT:
+	case CKA_ISSUER:
+	case CKA_SERIAL_NUMBER:
+		return lookup_assertion_value (self, session, attr);
+
+	default:
+		break;
+	};
+
+	return GKM_OBJECT_CLASS (gkm_xdg_trust_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gkm_xdg_trust_init (GkmXdgTrust *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKM_XDG_TYPE_TRUST, GkmXdgTrustPrivate);
+	self->pv->assertions = g_hash_table_new (gkm_util_ulong_hash, gkm_util_ulong_equal);
+}
+
+static void
+gkm_xdg_trust_finalize (GObject *obj)
+{
+	GkmXdgTrust *self = GKM_XDG_TRUST (obj);
+
+	g_assert (self->pv->assertions);
+	g_hash_table_destroy (self->pv->assertions);
+	self->pv->assertions = NULL;
+
+	g_free (self->pv->attrs);
+	self->pv->attrs = NULL;
+	self->pv->n_attrs = 0;
+
+	G_OBJECT_CLASS (gkm_xdg_trust_parent_class)->finalize (obj);
+}
+
+static void
+gkm_xdg_trust_class_init (GkmXdgTrustClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
+
+	gobject_class->finalize = gkm_xdg_trust_finalize;
+	gkm_class->get_attribute = gkm_xdg_trust_get_attribute;
+
+	g_type_class_add_private (klass, sizeof (GkmXdgTrustPrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+void
+gkm_xdg_trust_netscape_register_assertion (GkmXdgTrustAssertion *assertion)
+{
+	GHashTable *netscape_trusts;
+	GkmXdgTrustLevel level;
+	const gchar *purpose;
+
+	g_return_if_fail (GKM_IS_MODULE (module));
+	g_return_if_fail (GKM_XDG_IS_TRUST_ASSERTION (assertion));
+
+	trust = lookup_or_create_matching_netscape_trust (assertion);
+
+	level = gkm_xdg_trust_get_level (assertion);
+	purpose = gkm_xdg_trust_get_purpose (assertion);
+	g_return_if_fail (purpose);
+
+	type = netscape_type_for_purpose (purpose);
+	value = netscape_trust_for_level (level);
+
+}
diff --git a/pkcs11/xdg-store/gkm-xdg-trust-netscape.h b/pkcs11/xdg-store/gkm-xdg-trust-netscape.h
new file mode 100644
index 0000000..c8060d2
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-trust-netscape.h
@@ -0,0 +1,59 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKM_XDG_TRUST_NETSCAPE_H__
+#define __GKM_XDG_TRUST_NETSCAPE_H__
+
+#include <glib-object.h>
+
+#include "gkm/gkm-object.h"
+
+#define GKM_XDG_TYPE_TRUST_NETSCAPE      (gkm_xdg_trust_netscape_get_type ())
+#define GKM_XDG_TRUST_NETSCAPE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_XDG_TYPE_TRUST_NETSCAPE, GkmXdgTrustNetscape))
+#define GKM_XDG_TRUST_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_XDG_TYPE_TRUST_NETSCAPE, GkmXdgTrustNetscapeClass))
+#define GKM_XDG_IS_TRUST(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_XDG_TYPE_TRUST_NETSCAPE))
+#define GKM_XDG_IS_TRUST_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_XDG_TYPE_TRUST_NETSCAPE))
+#define GKM_XDG_TRUST_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_XDG_TYPE_TRUST_NETSCAPE, GkmXdgTrustClass))
+
+typedef struct _GkmXdgTrustNetscape GkmXdgTrustNetscape;
+typedef struct _GkmXdgTrustNetscapeClass GkmXdgTrustNetscapeClass;
+typedef struct _GkmXdgTrustNetscapePrivate GkmXdgTrustNetscapePrivate;
+
+struct _GkmXdgTrustNetscape {
+	GkmObject parent;
+	GkmXdgTrustNetscapePrivate *pv;
+};
+
+struct _GkmXdgTrustNetscapeClass {
+	GkmObjectClass parent_class;
+};
+
+GType                 gkm_xdg_trust_netscape_get_type                   (void);
+
+void                  gkm_xdg_trust_netscape_add_assertion_for_sha1     (GModule *module,
+                                                                         gpointer sha1_hash,
+                                                                         gsize n_sha1_hash);
+
+void                  gkm_xdg_trust_netscape_add_assertion_for_issuer   (GModule *module,
+                                                                         gpointer sha1_hash,
+                                                                         gsize n_sha1_hash);
+
+#endif /* __GKM_XDG_TRUST_NETSCAPE_H__ */
diff --git a/pkcs11/xdg-store/gkm-xdg-trust.c b/pkcs11/xdg-store/gkm-xdg-trust.c
index d32cb59..ff976e8 100644
--- a/pkcs11/xdg-store/gkm-xdg-trust.c
+++ b/pkcs11/xdg-store/gkm-xdg-trust.c
@@ -24,26 +24,42 @@
 #include "gkm-xdg-trust.h"
 
 #include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 
+#include "gkm/gkm-assertion.h"
 #include "gkm/gkm-attributes.h"
 #include "gkm/gkm-object.h"
+#include "gkm/gkm-oids.h"
 #include "gkm/gkm-serializable.h"
 #include "gkm/gkm-session.h"
 #include "gkm/gkm-transaction.h"
 #include "gkm/gkm-util.h"
 
-#include "pkcs11/pkcs11g.h"
+#include "pkcs11/pkcs11i.h"
 #include "pkcs11/pkcs11n.h"
 
 #include <libtasn1.h>
 
 #include <glib/gi18n.h>
 
+/* COMPAT: netscape's usages */
+typedef struct _NetscapeFlags {
+	CK_ULONG server_auth;
+	CK_ULONG client_auth;
+	CK_ULONG code_signing;
+	CK_ULONG email_protection;
+	CK_ULONG ipsec_end_system;
+	CK_ULONG ipsec_tunnel;
+	CK_ULONG ipsec_user;
+	CK_ULONG time_stamping;
+} NetscapeFlags;
+
 struct _GkmXdgTrustPrivate {
 	GNode *asn;
-	GHashTable *pairs;
+	GHashTable *assertions;
 	gpointer data;
 	gsize n_data;
+	NetscapeFlags netscape;
 };
 
 /* From asn1-def-xdg.c */
@@ -51,41 +67,17 @@ extern const ASN1_ARRAY_TYPE xdg_asn1_tab[];
 
 static void gkm_xdg_trust_serializable (GkmSerializableIface *iface);
 
-G_DEFINE_TYPE_EXTENDED (GkmXdgTrust, gkm_xdg_trust, GKM_TYPE_OBJECT, 0,
+G_DEFINE_TYPE_EXTENDED (GkmXdgTrust, gkm_xdg_trust, GKM_TYPE_TRUST, 0,
                         G_IMPLEMENT_INTERFACE (GKM_TYPE_SERIALIZABLE, gkm_xdg_trust_serializable));
 
 /* -----------------------------------------------------------------------------
  * QUARKS
  */
 
-static GQuark OID_HASH_SHA1;
-static GQuark OID_HASH_MD5;
-
-static GQuark OID_USAGE_DIGITAL_SIGNATURE;
-static GQuark OID_USAGE_NON_REPUDIATION;
-static GQuark OID_USAGE_KEY_ENCIPHERMENT;
-static GQuark OID_USAGE_DATA_ENCIPHERMENT;
-static GQuark OID_USAGE_KEY_AGREEMENT;
-static GQuark OID_USAGE_KEY_CERT_SIGN;
-static GQuark OID_USAGE_CRL_SIGN;
-static GQuark OID_USAGE_ENCIPHER_ONLY;
-
-/* OID's for these purposes */
-static GQuark OID_PURPOSE_SERVER_AUTH;
-static GQuark OID_PURPOSE_CLIENT_AUTH;
-static GQuark OID_PURPOSE_CODE_SIGNING;
-static GQuark OID_PURPOSE_EMAIL;
-static GQuark OID_PURPOSE_TIME_STAMPING;
-static GQuark OID_PURPOSE_IPSEC_ENDPOINT;
-static GQuark OID_PURPOSE_IPSEC_TUNNEL;
-static GQuark OID_PURPOSE_IPSEC_USER;
-static GQuark OID_PURPOSE_IKE_INTERMEDIATE;
-
 static GQuark TRUST_UNKNOWN;
 static GQuark TRUST_UNTRUSTED;
-static GQuark TRUST_MUST_VERIFY;
 static GQuark TRUST_TRUSTED;
-static GQuark TRUST_TRUSTED_DELEGATOR;
+static GQuark TRUST_TRUSTED_ANCHOR;
 
 static void
 init_quarks (void)
@@ -97,34 +89,10 @@ init_quarks (void)
 		#define QUARK(name, value) \
 			name = g_quark_from_static_string(value)
 
-		QUARK (OID_HASH_SHA1, "1.3.14.3.2.26");
-		QUARK (OID_HASH_MD5, "1.2.840.113549.2.5");
-
-		/* These OIDs are in GNOME's space */
-		QUARK (OID_USAGE_DIGITAL_SIGNATURE, "1.3.6.1.4.1.3319.1.6.3.128");
-		QUARK (OID_USAGE_NON_REPUDIATION, "1.3.6.1.4.1.3319.1.6.3.64");
-		QUARK (OID_USAGE_KEY_ENCIPHERMENT, "1.3.6.1.4.1.3319.1.6.3.32");
-		QUARK (OID_USAGE_DATA_ENCIPHERMENT, "1.3.6.1.4.1.3319.1.6.3.16");
-		QUARK (OID_USAGE_KEY_AGREEMENT, "1.3.6.1.4.1.3319.1.6.3.8");
-		QUARK (OID_USAGE_KEY_CERT_SIGN, "1.3.6.1.4.1.3319.1.6.3.4");
-		QUARK (OID_USAGE_CRL_SIGN, "1.3.6.1.4.1.3319.1.6.3.2");
-		QUARK (OID_USAGE_ENCIPHER_ONLY, "1.3.6.1.4.1.3319.1.6.3.1");
-
-		QUARK (OID_PURPOSE_SERVER_AUTH, "1.3.6.1.5.5.7.3.1");
-		QUARK (OID_PURPOSE_CLIENT_AUTH, "1.3.6.1.5.5.7.3.2");
-		QUARK (OID_PURPOSE_CODE_SIGNING, "1.3.6.1.5.5.7.3.3");
-		QUARK (OID_PURPOSE_EMAIL, "1.3.6.1.5.5.7.3.4");
-		QUARK (OID_PURPOSE_TIME_STAMPING, "1.3.6.1.5.5.7.3.8");
-		QUARK (OID_PURPOSE_IPSEC_ENDPOINT, "1.3.6.1.5.5.7.3.5");
-		QUARK (OID_PURPOSE_IPSEC_TUNNEL, "1.3.6.1.5.5.7.3.6");
-		QUARK (OID_PURPOSE_IPSEC_USER, "1.3.6.1.5.5.7.3.7");
-		QUARK (OID_PURPOSE_IKE_INTERMEDIATE, "1.3.6.1.5.5.8.2.2");
-
 		QUARK (TRUST_UNKNOWN, "trustUnknown");
 		QUARK (TRUST_UNTRUSTED, "untrusted");
-		QUARK (TRUST_MUST_VERIFY, "mustVerify");
 		QUARK (TRUST_TRUSTED, "trusted");
-		QUARK (TRUST_TRUSTED_DELEGATOR, "trustedDelegator");
+		QUARK (TRUST_TRUSTED_ANCHOR, "trustedAnchor");
 
 		#undef QUARK
 
@@ -136,25 +104,6 @@ init_quarks (void)
  * INTERNAL
  */
 
-static CK_ULONG
-lookup_usage (GkmXdgTrust *self, GQuark purpose)
-{
-	CK_ULONG *trust;
-
-	trust = g_hash_table_lookup (self->pv->pairs, GUINT_TO_POINTER (purpose));
-	if (!trust)
-		return CKT_NETSCAPE_TRUST_UNKNOWN;
-	else
-		return *trust;
-}
-
-static CK_RV
-trust_get_usage (GkmXdgTrust *self, GQuark purpose, CK_ATTRIBUTE_PTR attr)
-{
-	g_assert (GKM_XDG_IS_TRUST (self));
-	return gkm_attribute_set_ulong (attr, lookup_usage (self, purpose));
-}
-
 static CK_RV
 trust_get_der (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 {
@@ -164,10 +113,9 @@ trust_get_der (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 
 	g_assert (GKM_XDG_IS_TRUST (self));
 
-	node = egg_asn1x_node (self->pv->asn, "reference", "certReference", NULL);
-	g_return_val_if_fail (node, CKR_GENERAL_ERROR);
+	node = egg_asn1x_node (self->pv->asn, "reference", "certReference", part, NULL);
 
-	node = egg_asn1x_node (node, part, NULL);
+	/* If the assertion doesn't contain this info ... */
 	if (node == NULL)
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 
@@ -188,10 +136,9 @@ trust_get_integer (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 
 	g_assert (GKM_XDG_IS_TRUST (self));
 
-	node = egg_asn1x_node (self->pv->asn, "reference", "certReference", NULL);
-	g_return_val_if_fail (node, CKR_GENERAL_ERROR);
+	node = egg_asn1x_node (self->pv->asn, "reference", "certReference", part, NULL);
 
-	node = egg_asn1x_node (node, part, NULL);
+	/* If the assertion doesn't contain this info ... */
 	if (node == NULL)
 		return CKR_ATTRIBUTE_TYPE_INVALID;
 
@@ -203,44 +150,39 @@ trust_get_integer (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
 }
 
 static CK_RV
-trust_get_hash (GkmXdgTrust *self, GQuark oid, CK_ATTRIBUTE_PTR attr)
+trust_get_hash (GkmXdgTrust *self, GChecksumType ctype, CK_ATTRIBUTE_PTR attr)
 {
-	CK_RV rv = CKR_ATTRIBUTE_VALUE_INVALID;
-	GNode *digests, *digest;
-	gpointer hash;
-	gsize n_hash;
-	guint count, i;
-	GQuark check;
+	GNode *cert;
+	gconstpointer element;
+	gsize n_element;
 
-	digests = egg_asn1x_node (self->pv->asn, "reference", "certReference", "digests", NULL);
-	g_return_val_if_fail (digests, CKR_GENERAL_ERROR);
+	cert = egg_asn1x_node (self->pv->asn, "reference", "certComplete", NULL);
 
-	count = egg_asn1x_count (digests);
-	for (i = 0; i < count; ++i) {
-		digest = egg_asn1x_node (digests, i + 1, NULL);
-		g_return_val_if_fail (digest, CKR_GENERAL_ERROR);
-
-		check = egg_asn1x_get_oid_as_quark (egg_asn1x_node (digest, "algorithm", NULL));
-		if (oid == check) {
-			hash = egg_asn1x_get_string_as_raw (egg_asn1x_node (digest, "digest", NULL),
-			                                    NULL, &n_hash);
-			g_return_val_if_fail (hash, CKR_GENERAL_ERROR);
-
-			rv = gkm_attribute_set_data (attr, hash, n_hash);
-			g_free (hash);
-			break;
-		}
-	}
+	/* If it's not stored, then this attribute is not present */
+	if (cert == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
 
-	return rv;
+	element = egg_asn1x_get_raw_element (cert, &n_element);
+	g_return_val_if_fail (element, CKR_GENERAL_ERROR);
+
+	return gkm_attribute_set_checksum (attr, ctype, element, n_element);
 }
 
 static gboolean
-validate_der (CK_ATTRIBUTE_PTR attr)
+validate_der (CK_ATTRIBUTE_PTR attr, const gchar *asn_type)
 {
-	return attr->pValue != NULL &&
-	       attr->ulValueLen != (CK_ULONG)-1 &&
-	       egg_asn1x_element_length (attr->pValue, attr->ulValueLen) >= 0;
+	GNode *asn;
+
+	if (!attr->pValue || attr->ulValueLen == (CK_ULONG)-1)
+		return FALSE;
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, asn_type, attr->pValue, attr->ulValueLen);
+	if (!asn)
+		return FALSE;
+
+	/* Yes, this is an expensive check, but worthwhile */
+	egg_asn1x_destroy (asn);
+	return TRUE;
 }
 
 static gboolean
@@ -251,212 +193,277 @@ validate_integer (CK_ATTRIBUTE_PTR attr)
 	       attr->ulValueLen != (CK_ULONG)-1;
 }
 
-static gboolean
-validate_hash (CK_ATTRIBUTE_PTR attr, GChecksumType type)
-{
-	return attr->pValue != NULL &&
-	       attr->ulValueLen == g_checksum_type_get_length (type);
-}
-
-static void
-append_reference_hash (GNode *asn, GQuark oid, CK_ATTRIBUTE_PTR attr)
-{
-	GNode *node;
-
-	node = egg_asn1x_node (asn, "reference", "certReference", "digests", NULL);
-	g_return_if_fail (node);
-
-	/* Add another digest */
-	node = egg_asn1x_append (node);
-	g_return_if_fail (node);
-
-	egg_asn1x_set_oid_as_quark (egg_asn1x_node (node, "algorithm", NULL), oid);
-	egg_asn1x_set_string_as_raw (egg_asn1x_node (node, "digest", NULL),
-	                             g_memdup (attr->pValue, attr->ulValueLen),
-	                             attr->ulValueLen, g_free);
-}
-
 static GQuark
-trust_ulong_to_level_enum (CK_ULONG trust)
+assertion_type_to_level_enum (CK_ASSERTION_TYPE type)
 {
-	switch (trust) {
-	case CKT_NETSCAPE_TRUST_UNKNOWN:
-		return TRUST_UNKNOWN;
-	case CKT_NETSCAPE_UNTRUSTED:
+	switch (type) {
+	case CKT_G_CERTIFICATE_UNTRUSTED:
 		return TRUST_UNTRUSTED;
-	case CKT_NETSCAPE_TRUSTED_DELEGATOR:
-		return TRUST_TRUSTED_DELEGATOR;
+	case CKT_G_CERTIFICATE_TRUST_ANCHOR:
+		return TRUST_TRUSTED_ANCHOR;
 	case CKT_NETSCAPE_TRUSTED:
 		return TRUST_TRUSTED;
-	case CKT_NETSCAPE_MUST_VERIFY:
-		return TRUST_MUST_VERIFY;
 	default:
-		return -1;
+		return 0;
 	};
 }
 
-static CK_ULONG
-level_enum_to_trust_ulong (GQuark level)
+static gboolean
+level_enum_to_assertion_type (GQuark level, CK_ASSERTION_TYPE *type)
 {
-	if (level == TRUST_UNKNOWN)
-		return CKT_NETSCAPE_TRUST_UNKNOWN;
-	else if (level == TRUST_UNTRUSTED)
-		return CKT_NETSCAPE_UNTRUSTED;
-	else if (level == TRUST_TRUSTED_DELEGATOR)
-		return CKT_NETSCAPE_TRUSTED_DELEGATOR;
+	if (level == TRUST_UNTRUSTED)
+		*type = CKT_G_CERTIFICATE_UNTRUSTED;
+	else if (level == TRUST_TRUSTED_ANCHOR)
+		*type = CKT_G_CERTIFICATE_TRUST_ANCHOR;
 	else if (level == TRUST_TRUSTED)
-		return CKT_NETSCAPE_TRUSTED;
-	else if (level == TRUST_MUST_VERIFY)
-		return CKT_NETSCAPE_MUST_VERIFY;
+		*type = CKT_G_CERTIFICATE_TRUST_EXCEPTION;
+	else if (level == TRUST_UNKNOWN)
+		*type = 0;
 	else
-		return (CK_ULONG)-1;
+		return FALSE;
+	return TRUE;
 }
 
-static GkmObject*
-factory_create_trust (GkmSession *session, GkmTransaction *transaction,
-                      CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+static void
+init_netscape_trust (NetscapeFlags *netscape)
 {
-	GkmXdgTrust *trust;
-	CK_ATTRIBUTE_PTR serial, issuer, subject;
-	CK_ATTRIBUTE_PTR md5, sha1;
-	GNode *asn;
+	netscape->server_auth = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->client_auth = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->code_signing = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->email_protection = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->ipsec_end_system = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->ipsec_tunnel = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->ipsec_user = CKT_NETSCAPE_TRUST_UNKNOWN;
+	netscape->time_stamping = CKT_NETSCAPE_TRUST_UNKNOWN;
+}
 
-	g_return_val_if_fail (attrs || !n_attrs, NULL);
+static void
+parse_netscape_trust (NetscapeFlags *netscape, GQuark level, const gchar *purpose)
+{
+	CK_TRUST trust;
 
-	subject = gkm_attributes_find (attrs, n_attrs, CKA_SUBJECT);
-	serial = gkm_attributes_find (attrs, n_attrs, CKA_SERIAL_NUMBER);
-	issuer = gkm_attributes_find (attrs, n_attrs, CKA_ISSUER);
+	if (level == TRUST_UNTRUSTED)
+		trust = CKT_NETSCAPE_TRUSTED;
+	else if (level == TRUST_TRUSTED_ANCHOR)
+		trust = CKT_NETSCAPE_TRUSTED_DELEGATOR;
+	else if (level == TRUST_TRUSTED)
+		trust = CKT_NETSCAPE_TRUSTED;
+	else if (level == TRUST_UNKNOWN)
+		trust = CKT_NETSCAPE_TRUST_UNKNOWN;
+	else
+		return;
 
-	if (serial == NULL || issuer == NULL) {
-		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
-		return NULL;
-	}
+	if (g_str_equal (purpose, GKM_OID_EXTUSAGE_SERVER_AUTH))
+		netscape->server_auth = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_CLIENT_AUTH))
+		netscape->client_auth = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_CODE_SIGNING))
+		netscape->code_signing = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_EMAIL))
+		netscape->email_protection = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_IPSEC_ENDPOINT))
+		netscape->ipsec_end_system = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_IPSEC_TUNNEL))
+		netscape->ipsec_tunnel = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_IPSEC_USER))
+		netscape->ipsec_user = trust;
+	else if (g_str_equal (purpose, GKM_OID_EXTUSAGE_TIME_STAMPING))
+		netscape->time_stamping = trust;
+}
 
-	if (!validate_der (issuer) || (subject && !validate_der (subject))) {
-		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
-		return NULL;
-	}
+static void
+dispose_each_assertion (gpointer key, gpointer value, gpointer user_data)
+{
+	g_assert (GKM_IS_ASSERTION (value));
+	g_object_run_dispose (G_OBJECT (value));
+}
 
-	if (!validate_integer (serial)) {
-		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
-		return NULL;
-	}
+static GHashTable*
+create_assertions (void)
+{
+	return g_hash_table_new_full (gkm_util_memory_hash, gkm_util_memory_equal,
+	                              gkm_util_memory_free, gkm_util_dispose_unref);
+}
 
-	md5 = gkm_attributes_find (attrs, n_attrs, CKA_CERT_MD5_HASH);
-	sha1 = gkm_attributes_find (attrs, n_attrs, CKA_CERT_SHA1_HASH);
+static GkmAssertion*
+create_assertion (GkmXdgTrust *self, GNode *asn, NetscapeFlags *netscape)
+{
+	CK_ASSERTION_TYPE type;
+	GkmAssertion *assertion;
+	GQuark level;
+	gchar *purpose;
+	gchar *remote;
+	GNode *node;
 
-	if ((md5 && !validate_hash (md5, G_CHECKSUM_MD5)) ||
-	    (sha1 && !validate_hash (sha1, G_CHECKSUM_SHA1))) {
-		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+	/* Get the trust level */
+	level = egg_asn1x_get_enumerated (egg_asn1x_node (asn, "level", NULL));
+	if (level == 0)
+		g_return_val_if_reached (NULL);
+	if (!level_enum_to_assertion_type (level, &type))
+		g_message ("unsupported trust level %s in trust object", g_quark_to_string (level));
+	else if (type == 0)
 		return NULL;
-	}
 
-	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
-	g_return_val_if_fail (asn, NULL);
+	/* A purpose */
+	purpose = egg_asn1x_get_oid_as_string (egg_asn1x_node (asn, "purpose", NULL));
+	g_return_val_if_fail (purpose, NULL);
 
-	egg_asn1x_set_integer_as_raw (egg_asn1x_node (asn, "reference", "certReference", "serialNumber", NULL),
-	                              g_memdup (serial->pValue, serial->ulValueLen),
-	                              serial->ulValueLen, g_free);
-
-	egg_asn1x_set_raw_element (egg_asn1x_node (asn, "reference", "certReference", "issuer", NULL),
-	                           g_memdup (issuer->pValue, issuer->ulValueLen),
-	                           issuer->ulValueLen, g_free);
-
-	if (subject)
-		egg_asn1x_set_raw_element (egg_asn1x_node (asn, "reference", "certReference", "subject", NULL),
-		                           g_memdup (subject->pValue, issuer->ulValueLen),
-		                           issuer->ulValueLen, g_free);
+	/* A remote name */
+	node = egg_asn1x_node (asn, "remote", NULL);
+	if (egg_asn1x_have (node))
+		remote = egg_asn1x_get_string_as_utf8 (node, NULL);
+	else
+		remote = NULL;
 
-	if (md5)
-		append_reference_hash (asn, OID_HASH_MD5, md5);
-	if (sha1)
-		append_reference_hash (asn, OID_HASH_SHA1, sha1);
+	assertion = gkm_assertion_new (GKM_TRUST (self), type, purpose, remote);
 
-	trust = g_object_new (GKM_XDG_TYPE_TRUST,
-	                    "module", gkm_session_get_module (session),
-	                    "manager", gkm_manager_for_template (attrs, n_attrs, session),
-	                    NULL);
-	trust->pv->asn = asn;
+	/* Parse netscape trust flags */
+	if (remote == NULL)
+		parse_netscape_trust (netscape, level, purpose);
 
-	gkm_attributes_consume (attrs, n_attrs, CKA_CERT_MD5_HASH, CKA_CERT_SHA1_HASH,
-	                        CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER, G_MAXULONG);
+	g_free (purpose);
+	g_free (remote);
 
-	gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (trust),
-	                                      TRUE, attrs, n_attrs);
-	return GKM_OBJECT (trust);
+	return assertion;
 }
 
 static gboolean
-load_trust_pairs (GHashTable *pairs, GNode *asn)
+load_assertions (GkmXdgTrust *self, GNode *asn)
 {
-	GNode *pair;
+	gconstpointer element;
+	GHashTable *assertions;
+	GkmAssertion *assertion;
+	NetscapeFlags netscape;
+	gsize n_element;
+	GNode *node;
 	guint count, i;
-	gulong trust;
-	GQuark oid;
-	GQuark level;
 
-	g_assert (pairs);
+	g_assert (self);
 	g_assert (asn);
 
-	g_hash_table_remove_all (pairs);
+	assertions = create_assertions ();
+	init_netscape_trust (&netscape);
 
-	count = egg_asn1x_count (egg_asn1x_node (asn, "trusts", NULL));
+	count = egg_asn1x_count (egg_asn1x_node (asn, "assertions", NULL));
 
 	for (i = 0; i < count; ++i) {
-		pair = egg_asn1x_node (asn, "trusts", i + 1, NULL);
-		g_return_val_if_fail (pair, FALSE);
+		node = egg_asn1x_node (asn, "assertions", i + 1, NULL);
+		g_return_val_if_fail (node, FALSE);
 
-		/* Get the usage */
-		level = egg_asn1x_get_enumerated (egg_asn1x_node (pair, "level", NULL));
-		if (level == 0)
-			g_return_val_if_reached (FALSE);
+		/* We use the raw DER encoding as an assertion */
+		element = egg_asn1x_get_raw_element (node, &n_element);
+		g_return_val_if_fail (node, FALSE);
 
-		trust = level_enum_to_trust_ulong (level);
-		if (trust == (CK_ULONG)-1) {
-			g_message ("unsupported trust level %u in trust object", (guint)level);
-			continue;
-		}
+		/* Double check that this is valid, because it's how we hash */
+		g_assert (egg_asn1x_element_length (element, n_element) == n_element);
+
+		/* Already have this assertion? */
+		assertion = g_hash_table_lookup (self->pv->assertions, element);
+		if (assertion) {
+			g_object_ref (assertion);
+			g_hash_table_remove (self->pv->assertions, element);
 
-		/* A key usage */
-		oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (pair, "purpose", NULL));
-		g_return_val_if_fail (oid, FALSE);
+		/* Create a new assertion */
+		} else {
+			assertion = create_assertion (self, node, &netscape);
+		}
 
-		g_hash_table_replace (pairs, GUINT_TO_POINTER (oid),
-		                      gkm_util_ulong_alloc (trust));
+		if (assertion)
+			g_hash_table_insert (assertions, g_memdup (element, n_element), assertion);
 	}
 
+	/* Override the stored assertions and netscape trust */
+	g_hash_table_foreach (self->pv->assertions, dispose_each_assertion, NULL);
+	g_hash_table_unref (self->pv->assertions);
+	self->pv->assertions = assertions;
+	memcpy (&self->pv->netscape, &netscape, sizeof (netscape));
+
 	return TRUE;
 }
 
 static gboolean
-save_trust_pairs (GHashTable *pairs, GNode *asn)
+save_assertions (GkmXdgTrust *self, GNode *asn)
 {
+	GkmAssertion *assertion;
 	GHashTableIter iter;
 	GNode *pair, *node;
-	gpointer key, value;
+	const gchar *purpose;
+	const gchar *remote;
+	gpointer value;
 	GQuark level;
-	GQuark oid;
 
-	g_assert (pairs);
+	g_assert (GKM_XDG_IS_TRUST (self));
 	g_assert (asn);
 
 	node = egg_asn1x_node (asn, "trusts", NULL);
 	egg_asn1x_clear (node);
 
-	g_hash_table_iter_init (&iter, pairs);
-	while (g_hash_table_iter_next (&iter, &key, &value)) {
-		oid = GPOINTER_TO_UINT (key);
-		level = trust_ulong_to_level_enum (*((CK_ULONG_PTR)value));
+	g_hash_table_iter_init (&iter, self->pv->assertions);
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
+		assertion = GKM_ASSERTION (value);
+		level = assertion_type_to_level_enum (gkm_assertion_get_trust_type (assertion));
+		purpose = gkm_assertion_get_purpose (assertion);
+		remote = gkm_assertion_get_remote (assertion);
 
 		pair = egg_asn1x_append (node);
 		g_return_val_if_fail (pair, FALSE);
 
-		egg_asn1x_set_oid_as_quark (egg_asn1x_node (pair, "purpose", NULL), oid);
+		egg_asn1x_set_oid_as_string (egg_asn1x_node (pair, "purpose", NULL), purpose);
 		egg_asn1x_set_enumerated (egg_asn1x_node (pair, "level", NULL), level);
+
+		if (remote) {
+			egg_asn1x_set_string_as_utf8 (egg_asn1x_node (pair, "remote", NULL),
+			                              g_strdup (remote), g_free);
+		}
 	}
 
 	return TRUE;
 }
+
+static GkmXdgTrust*
+create_trust_for_reference (GkmModule *module, GkmManager *manager,
+                            CK_ATTRIBUTE_PTR serial, CK_ATTRIBUTE_PTR issuer)
+{
+	GkmXdgTrust *trust;
+	GNode *asn;
+
+	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
+	g_return_val_if_fail (asn, NULL);
+
+	egg_asn1x_set_integer_as_raw (egg_asn1x_node (asn, "reference", "certReference", "serialNumber", NULL),
+	                              g_memdup (serial->pValue, serial->ulValueLen),
+	                              serial->ulValueLen, g_free);
+
+	egg_asn1x_set_raw_element (egg_asn1x_node (asn, "reference", "certReference", "issuer", NULL),
+	                           g_memdup (issuer->pValue, issuer->ulValueLen),
+	                           issuer->ulValueLen, g_free);
+
+	trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL);
+	trust->pv->asn = asn;
+
+	return trust;
+}
+
+static GkmXdgTrust*
+create_trust_for_certificate (GkmModule *module, GkmManager *manager,
+                              CK_ATTRIBUTE_PTR cert)
+{
+	GkmXdgTrust *trust;
+	GNode *asn;
+
+	asn = egg_asn1x_create (xdg_asn1_tab, "trust-1");
+	g_return_val_if_fail (asn, NULL);
+
+	egg_asn1x_set_raw_element (egg_asn1x_node (asn, "reference", "certComplete", NULL),
+	                           g_memdup (cert->pValue, cert->ulValueLen),
+	                           cert->ulValueLen, g_free);
+
+	trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL);
+	trust->pv->asn = asn;
+
+	return trust;
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -475,41 +482,25 @@ gkm_xdg_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_
 	case CKA_CLASS:
 		return gkm_attribute_set_ulong (attr, CKO_NETSCAPE_TRUST);
 	case CKA_MODIFIABLE:
-		return gkm_attribute_set_bool (attr, CK_TRUE);
-
-	/* Key restrictions */
-	case CKA_TRUST_DIGITAL_SIGNATURE:
-		return trust_get_usage (self, OID_USAGE_DIGITAL_SIGNATURE, attr);
-	case CKA_TRUST_NON_REPUDIATION:
-		return trust_get_usage (self, OID_USAGE_NON_REPUDIATION, attr);
-	case CKA_TRUST_KEY_ENCIPHERMENT:
-		return trust_get_usage (self, OID_USAGE_KEY_ENCIPHERMENT, attr);
-	case CKA_TRUST_DATA_ENCIPHERMENT:
-		return trust_get_usage (self, OID_USAGE_DATA_ENCIPHERMENT, attr);
-	case CKA_TRUST_KEY_AGREEMENT:
-		return trust_get_usage (self, OID_USAGE_KEY_AGREEMENT, attr);
-	case CKA_TRUST_KEY_CERT_SIGN:
-		return trust_get_usage (self, OID_USAGE_KEY_CERT_SIGN, attr);
-	case CKA_TRUST_CRL_SIGN:
-		return trust_get_usage (self, OID_USAGE_CRL_SIGN, attr);
+		return gkm_attribute_set_bool (attr, CK_FALSE);
 
 	/* Various trust flags */
 	case CKA_TRUST_SERVER_AUTH:
-		return trust_get_usage (self, OID_PURPOSE_SERVER_AUTH, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.server_auth);
 	case CKA_TRUST_CLIENT_AUTH:
-		return trust_get_usage (self, OID_PURPOSE_CLIENT_AUTH, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.client_auth);
 	case CKA_TRUST_CODE_SIGNING:
-		return trust_get_usage (self, OID_PURPOSE_CODE_SIGNING, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.code_signing);
 	case CKA_TRUST_EMAIL_PROTECTION:
-		return trust_get_usage (self, OID_PURPOSE_EMAIL, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.email_protection);
 	case CKA_TRUST_IPSEC_END_SYSTEM:
-		return trust_get_usage (self, OID_PURPOSE_IPSEC_ENDPOINT, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.ipsec_end_system);
 	case CKA_TRUST_IPSEC_TUNNEL:
-		return trust_get_usage (self, OID_PURPOSE_IPSEC_TUNNEL, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.ipsec_tunnel);
 	case CKA_TRUST_IPSEC_USER:
-		return trust_get_usage (self, OID_PURPOSE_IPSEC_USER, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.ipsec_user);
 	case CKA_TRUST_TIME_STAMPING:
-		return trust_get_usage (self, OID_PURPOSE_TIME_STAMPING, attr);
+		return gkm_attribute_set_ulong (attr, self->pv->netscape.time_stamping);
 
 	/* Certificate reference values */
 	case CKA_SUBJECT:
@@ -521,9 +512,9 @@ gkm_xdg_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_
 
 	/* Certificate hash values */
 	case CKA_CERT_MD5_HASH:
-		return trust_get_hash (self, OID_HASH_MD5, attr);
+		return trust_get_hash (self, G_CHECKSUM_MD5, attr);
 	case CKA_CERT_SHA1_HASH:
-		return trust_get_hash (self, OID_HASH_SHA1, attr);
+		return trust_get_hash (self, G_CHECKSUM_SHA1, attr);
 
 	default:
 		break;
@@ -533,90 +524,10 @@ gkm_xdg_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_
 }
 
 static void
-gkm_xdg_trust_set_attribute (GkmObject *base, GkmSession *session,
-                             GkmTransaction* transaction, CK_ATTRIBUTE* attr)
-{
-	GkmXdgTrust *self = GKM_XDG_TRUST (base);
-	CK_ULONG value;
-	GQuark oid = 0;
-	CK_RV rv;
-
-	switch (attr->type)
-	{
-
-	/* Key restrictions */
-	case CKA_TRUST_DIGITAL_SIGNATURE:
-		oid = OID_USAGE_DIGITAL_SIGNATURE;
-		break;
-	case CKA_TRUST_NON_REPUDIATION:
-		oid = OID_USAGE_NON_REPUDIATION;
-		break;
-	case CKA_TRUST_KEY_ENCIPHERMENT:
-		oid = OID_USAGE_KEY_ENCIPHERMENT;
-		break;
-	case CKA_TRUST_DATA_ENCIPHERMENT:
-		oid = OID_USAGE_DATA_ENCIPHERMENT;
-		break;
-	case CKA_TRUST_KEY_AGREEMENT:
-		oid = OID_USAGE_KEY_AGREEMENT;
-		break;
-	case CKA_TRUST_KEY_CERT_SIGN:
-		oid = OID_USAGE_KEY_CERT_SIGN;
-		break;
-	case CKA_TRUST_CRL_SIGN:
-		oid = OID_USAGE_CRL_SIGN;
-		break;
-
-	/* Various trust flags */
-	case CKA_TRUST_SERVER_AUTH:
-		oid = OID_PURPOSE_SERVER_AUTH;
-		break;
-	case CKA_TRUST_CLIENT_AUTH:
-		oid = OID_PURPOSE_CLIENT_AUTH;
-		break;
-	case CKA_TRUST_CODE_SIGNING:
-		oid = OID_PURPOSE_CODE_SIGNING;
-		break;
-	case CKA_TRUST_EMAIL_PROTECTION:
-		oid = OID_PURPOSE_EMAIL;
-		break;
-	case CKA_TRUST_IPSEC_END_SYSTEM:
-		oid = OID_PURPOSE_IPSEC_ENDPOINT;
-		break;
-	case CKA_TRUST_IPSEC_TUNNEL:
-		oid = OID_PURPOSE_IPSEC_TUNNEL;
-		break;
-	case CKA_TRUST_IPSEC_USER:
-		oid = OID_PURPOSE_IPSEC_USER;
-		break;
-	case CKA_TRUST_TIME_STAMPING:
-		oid = OID_PURPOSE_TIME_STAMPING;
-		break;
-
-	default:
-		break;
-	};
-
-	if (oid != 0) {
-		rv = gkm_attribute_get_ulong (attr, &value);
-		if (rv != CKR_OK)
-			gkm_transaction_fail (transaction, rv);
-		else if (trust_ulong_to_level_enum (value) < 0)
-			gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
-		else
-			g_hash_table_replace (self->pv->pairs, GUINT_TO_POINTER (oid),
-			                      gkm_util_ulong_alloc (value));
-		return;
-	}
-
-	GKM_OBJECT_CLASS (gkm_xdg_trust_parent_class)->set_attribute (base, session, transaction, attr);
-}
-
-static void
 gkm_xdg_trust_init (GkmXdgTrust *self)
 {
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GKM_XDG_TYPE_TRUST, GkmXdgTrustPrivate);
-	self->pv->pairs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gkm_util_ulong_free);
+	self->pv->assertions = create_assertions ();
 }
 
 static void
@@ -628,9 +539,9 @@ gkm_xdg_trust_finalize (GObject *obj)
 		egg_asn1x_destroy (self->pv->asn);
 	self->pv->asn = NULL;
 
-	if (self->pv->pairs)
-		g_hash_table_destroy (self->pv->pairs);
-	self->pv->pairs = NULL;
+	if (self->pv->assertions)
+		g_hash_table_destroy (self->pv->assertions);
+	self->pv->assertions = NULL;
 
 	G_OBJECT_CLASS (gkm_xdg_trust_parent_class)->finalize (obj);
 }
@@ -643,7 +554,6 @@ gkm_xdg_trust_class_init (GkmXdgTrustClass *klass)
 
 	gobject_class->finalize = gkm_xdg_trust_finalize;
 	gkm_class->get_attribute = gkm_xdg_trust_get_attribute;
-	gkm_class->set_attribute = gkm_xdg_trust_set_attribute;
 
 	g_type_class_add_private (klass, sizeof (GkmXdgTrustPrivate));
 
@@ -673,7 +583,7 @@ gkm_xdg_trust_real_load (GkmSerializable *base, GkmSecret *login, gconstpointer
 	}
 
 	/* Next parse out all the pairs */
-	if (!load_trust_pairs (self->pv->pairs, asn)) {
+	if (!load_assertions (self, asn)) {
 		egg_asn1x_destroy (asn);
 		g_free (copy);
 		return FALSE;
@@ -699,7 +609,7 @@ gkm_xdg_trust_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data
 	g_return_val_if_fail (n_data, FALSE);
 	g_return_val_if_fail (self->pv->asn, FALSE);
 
-	if (!save_trust_pairs (self->pv->pairs, self->pv->asn))
+	if (!save_assertions (self, self->pv->asn))
 		return FALSE;
 
 	*data = egg_asn1x_encode (self->pv->asn, NULL, n_data);
@@ -730,22 +640,57 @@ gkm_xdg_trust_serializable (GkmSerializableIface *iface)
  * PUBLIC
  */
 
-
-GkmFactory*
-gkm_xdg_trust_get_factory (void)
+GkmTrust*
+gkm_xdg_trust_create_for_assertion (GkmModule *module, GkmManager *manager,
+                                    GkmTransaction *transaction,
+                                    CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
 {
-	static CK_OBJECT_CLASS klass = CKO_NETSCAPE_TRUST;
 
-	static CK_ATTRIBUTE attributes[] = {
-		{ CKA_CLASS, &klass, sizeof (klass) },
-	};
+	CK_ATTRIBUTE_PTR serial, issuer, cert;
+	GkmXdgTrust *trust;
 
-	static GkmFactory factory = {
-		attributes,
-		G_N_ELEMENTS (attributes),
-		factory_create_trust
-	};
+	g_return_val_if_fail (GKM_IS_MODULE (module), NULL);
+	g_return_val_if_fail (GKM_IS_MANAGER (manager), NULL);
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
 
-	init_quarks ();
-	return &factory;
+	serial = gkm_attributes_find (attrs, n_attrs, CKA_SERIAL_NUMBER);
+	issuer = gkm_attributes_find (attrs, n_attrs, CKA_ISSUER);
+	cert = gkm_attributes_find (attrs, n_attrs, CKA_G_CERTIFICATE_VALUE);
+
+	/* A trust object with just serial + issuer */
+	if (serial != NULL && issuer != NULL) {
+		if (cert != NULL) {
+			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+			return NULL;
+		}
+		if (!validate_der (issuer, "Name") || !validate_integer (serial)) {
+			gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+			return NULL;
+		}
+
+		trust = create_trust_for_reference (module, manager, serial, issuer);
+
+	/* A trust object with a full certificate */
+	} else if (cert != NULL) {
+		if (serial != NULL || issuer != NULL) {
+			gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+			return NULL;
+		}
+		if (!validate_der (cert, "TBSCertificate")) {
+			gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+			return NULL;
+		}
+
+		trust = create_trust_for_certificate (module, manager, cert);
+
+	/* Not sure what this is */
+	} else {
+		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
+
+	gkm_attributes_consume (attrs, n_attrs, CKA_G_CERTIFICATE_VALUE, CKA_ISSUER,
+	                        CKA_SERIAL_NUMBER, G_MAXULONG);
+
+	return GKM_TRUST (trust);
 }
diff --git a/pkcs11/xdg-store/gkm-xdg-trust.h b/pkcs11/xdg-store/gkm-xdg-trust.h
index 2780d2e..2e22218 100644
--- a/pkcs11/xdg-store/gkm-xdg-trust.h
+++ b/pkcs11/xdg-store/gkm-xdg-trust.h
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include "gkm/gkm-object.h"
+#include "gkm/gkm-trust.h"
 
 #define GKM_XDG_FACTORY_TRUST            (gkm_xdg_trust_get_factory ())
 #define GKM_XDG_TYPE_TRUST               (gkm_xdg_trust_get_type ())
@@ -39,16 +40,24 @@ typedef struct _GkmXdgTrustClass GkmXdgTrustClass;
 typedef struct _GkmXdgTrustPrivate GkmXdgTrustPrivate;
 
 struct _GkmXdgTrust {
-	GkmObject parent;
+	GkmTrust parent;
 	GkmXdgTrustPrivate *pv;
 };
 
 struct _GkmXdgTrustClass {
-	GkmObjectClass parent_class;
+	GkmTrustClass parent_class;
 };
 
 GType                 gkm_xdg_trust_get_type               (void);
 
-GkmFactory*           gkm_xdg_trust_get_factory            (void);
+GkmTrust*             gkm_xdg_trust_create_for_assertion   (GkmModule *module,
+                                                            GkmManager *manager,
+                                                            GkmTransaction *transaction,
+                                                            CK_ATTRIBUTE_PTR attrs,
+                                                            CK_ULONG n_attrs);
+
+GkmAssertion*         gkm_xdg_trust_add_assertion          (GkmTrust *trust,
+                                                            GkmTrustLevel level,
+                                                            const char *purpose);
 
 #endif /* __GKM_XDG_TRUST_H__ */
diff --git a/pkcs11/xdg-store/xdg.asn b/pkcs11/xdg-store/xdg.asn
index 8358a25..bb7ccf8 100644
--- a/pkcs11/xdg-store/xdg.asn
+++ b/pkcs11/xdg-store/xdg.asn
@@ -6,42 +6,43 @@ BEGIN
 
 -- This file contains definitions for keyring
 
-TrustDigest ::= SEQUENCE {
-	algorithm               OBJECT IDENTIFIER,
-	digest                  OCTET STRING
-}
-
-TrustDigests ::= SEQUENCE OF TrustDigest
-
 TrustLevel ::= ENUMERATED {
-	trustUnknown         (0),
+	unknown              (0),
 	untrusted            (1),
-	mustVerify           (2),
 	trusted              (3),
-	trustedDelegator     (4)
+	trustedAnchor        (4)
 }
 
-TrustPair ::= SEQUENCE {
+TrustAssertion ::= SEQUENCE {
 	purpose                 OBJECT IDENTIFIER,
-	level                   TrustLevel
+	level                   TrustLevel,
+	with                    OCTET STRING,
+
+	additions               SEQUENCE OF ANY
 }
 
-TrustPairs ::= SEQUENCE OF TrustPair
+TrustAssertions ::= SEQUENCE OF TrustAssertion
 
 CertReference ::= SEQUENCE {
 	serialNumber            INTEGER,
 	issuer                  ANY,
 	subject                 ANY OPTIONAL,
-	digests                 TrustDigests OPTIONAL
+
+	additions               SEQUENCE OF ANY
 }
 
 TrustReference ::= CHOICE {
-	certReference CertReference
+	certReference           [0] CertReference,
+	certComplete            [1] ANY,
+
+	additions               [2] ANY
 }
 
 trust-1 ::= SEQUENCE {
 	reference               TrustReference,
-	trusts                  TrustPairs
+	assertions              TrustAssertions,
+
+	additions               SEQUENCE OF ANY
 }
 
 END



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