[gnome-keyring/trust-store: 6/7] [xdg-store] Initial xdg-store with trust storage.



commit 95cd2d8d183b2d16a5875c1b8b43b2ab26f1e1ed
Author: Stef Walter <stef memberwebs com>
Date:   Sat Sep 18 17:17:41 2010 +0000

    [xdg-store] Initial xdg-store with trust storage.
    
    Initial xdg-store implementation. Only trust storage is implemented.
    xdg-store stores objects in the .local directory.

 configure.in                          |    2 +
 pkcs11/Makefile.am                    |    1 +
 pkcs11/xdg-store/Makefile.am          |   61 +++
 pkcs11/xdg-store/asn1-def-xdg.c       |   37 ++
 pkcs11/xdg-store/gkm-xdg-module.c     |  305 ++++++++++++++
 pkcs11/xdg-store/gkm-xdg-module.h     |   45 ++
 pkcs11/xdg-store/gkm-xdg-standalone.c |   51 +++
 pkcs11/xdg-store/gkm-xdg-store.h      |   29 ++
 pkcs11/xdg-store/gkm-xdg-trust.c      |  740 +++++++++++++++++++++++++++++++++
 pkcs11/xdg-store/gkm-xdg-trust.h      |   54 +++
 pkcs11/xdg-store/tests/Makefile.am    |    2 +
 pkcs11/xdg-store/tests/p11-tests.conf |    2 +
 pkcs11/xdg-store/xdg.asn              |   47 ++
 13 files changed, 1376 insertions(+), 0 deletions(-)
---
diff --git a/configure.in b/configure.in
index 9ae5645..4659302 100644
--- a/configure.in
+++ b/configure.in
@@ -700,6 +700,8 @@ pkcs11/ssh-store/Makefile
 pkcs11/ssh-store/tests/Makefile
 pkcs11/wrap-layer/Makefile
 pkcs11/wrap-layer/tests/Makefile
+pkcs11/xdg-store/Makefile
+pkcs11/xdg-store/tests/Makefile
 po/Makefile.in
 schema/Makefile
 testing/Makefile
diff --git a/pkcs11/Makefile.am b/pkcs11/Makefile.am
index c59d756..e24c173 100644
--- a/pkcs11/Makefile.am
+++ b/pkcs11/Makefile.am
@@ -17,4 +17,5 @@ SUBDIRS = . \
 	rpc-layer \
 	secret-store \
 	ssh-store \
+	xdg-store \
 	gnome2-store
diff --git a/pkcs11/xdg-store/Makefile.am b/pkcs11/xdg-store/Makefile.am
new file mode 100644
index 0000000..dfa5f3c
--- /dev/null
+++ b/pkcs11/xdg-store/Makefile.am
@@ -0,0 +1,61 @@
+
+INCLUDES = \
+	-I$(top_builddir) \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/pkcs11 \
+	$(GOBJECT_CFLAGS) \
+	$(LIBGCRYPT_CFLAGS) \
+	$(GLIB_CFLAGS)
+
+
+# ------------------------------------------------------------------------------
+# The xdg-store component code
+
+noinst_LTLIBRARIES = \
+	libgkm-xdg-store.la
+
+BUILT_SOURCES = \
+	asn1-def-xdg.c
+
+libgkm_xdg_store_la_SOURCES = \
+	gkm-xdg-store.h \
+	gkm-xdg-module.c gkm-xdg-module.h \
+	gkm-xdg-trust.c gkm-xdg-trust.h \
+	$(BUILT_SOURCES)
+
+asn1-def-xdg.c: xdg.asn
+	$(ASN1PARSER) -o asn1-def-xdg.c $(srcdir)/xdg.asn
+
+# ------------------------------------------------------------------------------
+# The standalone module
+
+moduledir = $(libdir)/gnome-keyring/devel/
+
+module_LTLIBRARIES = \
+	gkm-xdg-store-standalone.la
+
+gkm_xdg_store_standalone_la_LDFLAGS = \
+	-module -avoid-version \
+	-no-undefined -export-symbols-regex 'C_GetFunctionList'
+
+gkm_xdg_store_standalone_la_SOURCES = \
+	gkm-xdg-standalone.c
+
+gkm_xdg_store_standalone_la_LIBADD = \
+	libgkm-xdg-store.la \
+	$(top_builddir)/pkcs11/gkm/libgkm.la \
+	$(GOBJECT_LIBS) \
+	$(GTHREAD_LIBS) \
+	$(GLIB_LIBS) \
+	$(LIBGCRYPT_LIBS)
+
+
+# -------------------------------------------------------------------------------
+
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR =
+endif
+
+SUBDIRS = . $(TESTS_DIR)
diff --git a/pkcs11/xdg-store/asn1-def-xdg.c b/pkcs11/xdg-store/asn1-def-xdg.c
new file mode 100644
index 0000000..1d608be
--- /dev/null
+++ b/pkcs11/xdg-store/asn1-def-xdg.c
@@ -0,0 +1,37 @@
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <libtasn1.h>
+
+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"},
+  { "untrustedUsage", 1073741825, "1"},
+  { "mustVerify", 1073741825, "2"},
+  { "trustedUsage", 1073741825, "3"},
+  { "trustedDelegator", 1, "4"},
+  { "TrustPair", 1610612741, NULL },
+  { "purpose", 1073741836, NULL },
+  { "level", 2, "TrustLevel"},
+  { "TrustPairs", 1610612747, NULL },
+  { NULL, 2, "TrustPair"},
+  { "CertReference", 1610612741, NULL },
+  { "serialNumber", 1073741827, NULL },
+  { "issuer", 1073741837, NULL },
+  { "subject", 1073758221, NULL },
+  { "digests", 2, "TrustDigests"},
+  { "TrustReference", 1610612754, NULL },
+  { "certReference", 2, "CertReference"},
+  { "trust-1", 536870917, NULL },
+  { "reference", 1073741826, "TrustReference"},
+  { "trusts", 2, "TrustPairs"},
+  { NULL, 0, NULL }
+};
diff --git a/pkcs11/xdg-store/gkm-xdg-module.c b/pkcs11/xdg-store/gkm-xdg-module.c
new file mode 100644
index 0000000..1e7d81d
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-module.c
@@ -0,0 +1,305 @@
+/*
+ * 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-module.h"
+#include "gkm-xdg-store.h"
+#include "gkm-xdg-trust.h"
+
+#include "egg/egg-error.h"
+
+#include "gkm/gkm-file-tracker.h"
+#include "gkm/gkm-serializable.h"
+#include "gkm/gkm-util.h"
+
+#include <string.h>
+
+struct _GkmXdgModule {
+	GkmModule parent;
+	gchar *directory;
+	GHashTable *objects_by_path;
+	GkmFileTracker *tracker;
+	CK_TOKEN_INFO token_info;
+};
+
+static const CK_SLOT_INFO user_module_slot_info = {
+	"User Key Storage",
+	"Gnome Keyring",
+	CKF_TOKEN_PRESENT,
+	{ 0, 0 },
+	{ 0, 0 }
+};
+
+static const CK_TOKEN_INFO user_module_token_info = {
+	"User Key Storage",
+	"Gnome Keyring",
+	"1.0",
+	"1:XDG:DEFAULT", /* Unique serial number for manufacturer */
+	CKF_TOKEN_INITIALIZED,
+	CK_EFFECTIVELY_INFINITE,
+	CK_EFFECTIVELY_INFINITE,
+	CK_EFFECTIVELY_INFINITE,
+	CK_EFFECTIVELY_INFINITE,
+	1024,
+	1,
+	CK_UNAVAILABLE_INFORMATION,
+	CK_UNAVAILABLE_INFORMATION,
+	CK_UNAVAILABLE_INFORMATION,
+	CK_UNAVAILABLE_INFORMATION,
+	{ 0, 0 },
+	{ 0, 0 },
+	""
+};
+
+#define UNUSED_VALUE (GUINT_TO_POINTER (1))
+
+G_DEFINE_TYPE (GkmXdgModule, gkm_xdg_module, GKM_TYPE_MODULE);
+
+/* -----------------------------------------------------------------------------
+ * ACTUAL PKCS#11 Module Implementation
+ */
+
+/* Include all the module entry points */
+#include "gkm/gkm-module-ep.h"
+GKM_DEFINE_MODULE (gkm_xdg_module, GKM_TYPE_XDG_MODULE);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static GType
+type_from_path (const gchar *path)
+{
+	const gchar *ext;
+
+	ext = strrchr (path, '.');
+	if (ext == NULL)
+		return 0;
+
+	if (g_str_equal (ext, ".trust"))
+		return GKM_XDG_TYPE_TRUST;
+
+#if 0
+	else if (strcmp (extension, ".pkcs8") == 0)
+		return GKM_TYPE_GNOME2_PRIVATE_KEY;
+	else if (strcmp (extension, ".pub") == 0)
+		return GKM_TYPE_GNOME2_PUBLIC_KEY;
+	else if (strcmp (extension, ".cer") == 0)
+		return GKM_TYPE_CERTIFICATE;
+#endif
+
+	return 0;
+}
+
+static void
+file_load (GkmFileTracker *tracker, const gchar *path, GkmXdgModule *self)
+{
+	GkmObject *object;
+	GkmManager *manager;
+	gboolean added = FALSE;
+	GError *error = NULL;
+	GType type;
+	guchar *data;
+	gsize n_data;
+
+	g_return_if_fail (path);
+	g_return_if_fail (GKM_IS_XDG_MODULE (self));
+
+	manager = gkm_module_get_manager (GKM_MODULE (self));
+
+	/* Already have this object? */
+	object = g_hash_table_lookup (self->objects_by_path, path);
+	if (object == NULL) {
+
+		/* Figure out what type of object we're dealing with */
+		type = type_from_path (path);
+		if (type == 0) {
+			g_warning ("don't know how to load file in key store: %s", path);
+			return;
+		}
+
+		/* Create a new object for this identifier */
+		object = g_object_new (type,
+		                       "module", GKM_MODULE (self),
+		                       "manager", manager, NULL);
+		g_return_if_fail (GKM_IS_SERIALIZABLE (object));
+		g_return_if_fail (GKM_SERIALIZABLE_GET_INTERFACE (object)->extension);
+
+		added = TRUE;
+
+	} else {
+		g_object_ref (object);
+	}
+
+	/* Read the file in */
+	if (!g_file_get_contents (path, (gchar**)&data, &n_data, &error)) {
+		g_warning ("couldn't read file in key store: %s: %s", path,
+		           egg_error_message (error));
+		g_object_unref (object);
+		g_clear_error (&error);
+		return;
+
+	/* And load the data into it */
+	} else if (gkm_serializable_load (GKM_SERIALIZABLE (object), NULL, data, n_data)) {
+		if (added)
+			g_hash_table_insert (self->objects_by_path, g_strdup (path), g_object_ref (object));
+		gkm_object_expose (object, TRUE);
+
+	} else {
+		g_message ("failed to load file in user store: %s", path);
+		if (!added)
+			gkm_object_expose (object, FALSE);
+	}
+
+	g_object_unref (object);
+}
+
+static void
+file_remove (GkmFileTracker *tracker, const gchar *path, GkmXdgModule *self)
+{
+	g_return_if_fail (path);
+	g_return_if_fail (GKM_IS_XDG_MODULE (self));
+	g_hash_table_remove (self->objects_by_path, path);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static const CK_SLOT_INFO*
+gkm_xdg_module_real_get_slot_info (GkmModule *base)
+{
+	return &user_module_slot_info;
+}
+
+static const CK_TOKEN_INFO*
+gkm_xdg_module_real_get_token_info (GkmModule *base)
+{
+	GkmXdgModule *self = GKM_XDG_MODULE (base);
+
+	/* TODO: Update the info with current info */
+	return &self->token_info;
+}
+
+static void
+gkm_xdg_module_real_parse_argument (GkmModule *base, const gchar *name, const gchar *value)
+{
+	GkmXdgModule *self = GKM_XDG_MODULE (base);
+	if (g_str_equal (name, "directory")) {
+		g_free (self->directory);
+		self->directory = g_strdup (value);
+	}
+}
+
+static CK_RV
+gkm_xdg_module_real_refresh_token (GkmModule *base)
+{
+	GkmXdgModule *self = GKM_XDG_MODULE (base);
+	gkm_file_tracker_refresh (self->tracker, FALSE);
+	return CKR_OK;
+}
+
+static GObject*
+gkm_xdg_module_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+	GkmXdgModule *self = GKM_XDG_MODULE (G_OBJECT_CLASS (gkm_xdg_module_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);
+
+	if (!self->directory)
+		self->directory = g_build_filename (g_get_user_data_dir (), "keystore", NULL);
+
+	self->tracker = gkm_file_tracker_new (self->directory, "*.*", NULL);
+	g_signal_connect (self->tracker, "file-added", G_CALLBACK (file_load), self);
+	g_signal_connect (self->tracker, "file-changed", G_CALLBACK (file_load), self);
+	g_signal_connect (self->tracker, "file-removed", G_CALLBACK (file_remove), self);
+
+	return G_OBJECT (self);
+}
+
+static void
+gkm_xdg_module_init (GkmXdgModule *self)
+{
+	self->objects_by_path = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+	/* 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);
+}
+
+static void
+gkm_xdg_module_dispose (GObject *obj)
+{
+	GkmXdgModule *self = GKM_XDG_MODULE (obj);
+
+	if (self->tracker)
+		g_object_unref (self->tracker);
+	self->tracker = NULL;
+
+	g_hash_table_remove_all (self->objects_by_path);
+
+	G_OBJECT_CLASS (gkm_xdg_module_parent_class)->dispose (obj);
+}
+
+static void
+gkm_xdg_module_finalize (GObject *obj)
+{
+	GkmXdgModule *self = GKM_XDG_MODULE (obj);
+
+	g_assert (self->tracker == NULL);
+
+	g_hash_table_destroy (self->objects_by_path);
+	self->objects_by_path = NULL;
+
+	g_free (self->directory);
+	self->directory = NULL;
+
+	G_OBJECT_CLASS (gkm_xdg_module_parent_class)->finalize (obj);
+}
+
+static void
+gkm_xdg_module_class_init (GkmXdgModuleClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GkmModuleClass *module_class = GKM_MODULE_CLASS (klass);
+
+	gobject_class->constructor = gkm_xdg_module_constructor;
+	gobject_class->dispose = gkm_xdg_module_dispose;
+	gobject_class->finalize = gkm_xdg_module_finalize;
+
+	module_class->get_slot_info = gkm_xdg_module_real_get_slot_info;
+	module_class->get_token_info = gkm_xdg_module_real_get_token_info;
+	module_class->parse_argument = gkm_xdg_module_real_parse_argument;
+	module_class->refresh_token = gkm_xdg_module_real_refresh_token;
+}
+
+/* ----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+CK_FUNCTION_LIST_PTR
+gkm_xdg_store_get_functions (void)
+{
+	gkm_crypto_initialize ();
+	return gkm_xdg_module_function_list;
+}
diff --git a/pkcs11/xdg-store/gkm-xdg-module.h b/pkcs11/xdg-store/gkm-xdg-module.h
new file mode 100644
index 0000000..755fa6f
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-module.h
@@ -0,0 +1,45 @@
+/*
+ * 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_MODULE_H__
+#define __GKM_XDG_MODULE_H__
+
+#include <glib-object.h>
+
+#include "gkm/gkm-module.h"
+
+#define GKM_TYPE_XDG_MODULE               (gkm_xdg_module_get_type ())
+#define GKM_XDG_MODULE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_TYPE_XDG_MODULE, GkmXdgModule))
+#define GKM_XDG_MODULE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_TYPE_XDG_MODULE, GkmXdgModuleClass))
+#define GKM_IS_XDG_MODULE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_TYPE_XDG_MODULE))
+#define GKM_IS_XDG_MODULE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_TYPE_XDG_MODULE))
+#define GKM_XDG_MODULE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_TYPE_XDG_MODULE, GkmXdgModuleClass))
+
+typedef struct _GkmXdgModule GkmXdgModule;
+typedef struct _GkmXdgModuleClass GkmXdgModuleClass;
+
+struct _GkmXdgModuleClass {
+	GkmModuleClass parent_class;
+};
+
+GType               gkm_xdg_module_get_type               (void);
+
+#endif /* __GKM_XDG_MODULE_H__ */
diff --git a/pkcs11/xdg-store/gkm-xdg-standalone.c b/pkcs11/xdg-store/gkm-xdg-standalone.c
new file mode 100644
index 0000000..a539938
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-standalone.c
@@ -0,0 +1,51 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkm-gnome2-standalone.h - The user-store PKCS#11 code as a standalone module
+
+   Copyright (C) 2008, Stef Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gkm-xdg-store.h"
+
+#include "gkm/gkm-crypto.h"
+
+#include "egg/egg-secure-memory.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <glib-object.h>
+
+/* Module callbacks for secure memory */
+EGG_SECURE_GLIB_DEFINITIONS ();
+
+CK_RV
+C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
+{
+	if (!list)
+		return CKR_ARGUMENTS_BAD;
+
+	g_type_init ();
+	if (!g_thread_supported ())
+		g_thread_init (NULL);
+
+	*list = gkm_xdg_store_get_functions ();
+	return CKR_OK;
+}
diff --git a/pkcs11/xdg-store/gkm-xdg-store.h b/pkcs11/xdg-store/gkm-xdg-store.h
new file mode 100644
index 0000000..7943a9c
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-store.h
@@ -0,0 +1,29 @@
+/*
+ * 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_STORE_H__
+#define __GKM_XDG_STORE_H__
+
+#include "pkcs11/pkcs11.h"
+
+CK_FUNCTION_LIST_PTR  gkm_xdg_store_get_functions  (void);
+
+#endif /* __GKM_XDG_STORE_H__ */
diff --git a/pkcs11/xdg-store/gkm-xdg-trust.c b/pkcs11/xdg-store/gkm-xdg-trust.c
new file mode 100644
index 0000000..89235d1
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-trust.c
@@ -0,0 +1,740 @@
+/*
+ * 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.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 _GkmXdgTrustPrivate {
+	GNode *asn;
+	GHashTable *pairs;
+	gpointer data;
+	gsize n_data;
+};
+
+/* From asn1-def-xdg.c */
+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_XDG_TYPE_TRUST, 0,
+                        G_IMPLEMENT_INTERFACE (GKM_TYPE_SERIALIZABLE, gkm_xdg_trust_serializable));
+
+enum {
+	TRUST_UNKNOWN = 0,
+	TRUST_UNTRUSTED = 1,
+	TRUST_MUST_VERIFY = 2,
+	TRUST_TRUSTED = 3,
+	TRUST_TRUSTED_DELEGATOR = 4
+};
+
+/* -----------------------------------------------------------------------------
+ * 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 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_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");
+
+		#undef QUARK
+
+		g_once_init_leave (&quarks_inited, 1);
+	}
+}
+
+/* -----------------------------------------------------------------------------
+ * 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)
+{
+	GNode *node;
+	gconstpointer element;
+	gsize n_element;
+
+	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, part, NULL);
+	if (node == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	element = egg_asn1x_get_raw_element (node, &n_element);
+	return gkm_attribute_set_data (attr, element, n_element);
+}
+
+static CK_RV
+trust_get_integer (GkmXdgTrust *self, const gchar *part, CK_ATTRIBUTE_PTR attr)
+{
+	GNode *node;
+	gpointer integer;
+	gsize n_integer;
+	CK_RV rv;
+
+	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, part, NULL);
+	if (node == NULL)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	integer = egg_asn1x_get_integer_as_raw (node, NULL, &n_integer);
+	rv = gkm_attribute_set_data (attr, integer, n_integer);
+	g_free (integer);
+
+	return rv;
+}
+
+static CK_RV
+trust_get_hash (GkmXdgTrust *self, GQuark oid, CK_ATTRIBUTE_PTR attr)
+{
+	CK_RV rv = CKR_ATTRIBUTE_VALUE_INVALID;
+	GNode *digests, *digest;
+	gpointer hash;
+	gsize n_hash;
+	guint count, i;
+	GQuark check;
+
+	digests = egg_asn1x_node (self->pv->asn, "reference", "certReference", "digests", NULL);
+	g_return_val_if_fail (digests, CKR_GENERAL_ERROR);
+
+	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;
+		}
+	}
+
+	return rv;
+}
+
+static gboolean
+validate_der (CK_ATTRIBUTE_PTR attr)
+{
+	return attr->pValue != NULL &&
+	       attr->ulValueLen != (CK_ULONG)-1 &&
+	       egg_asn1x_element_length (attr->pValue, attr->ulValueLen) >= 0;
+}
+
+static gboolean
+validate_integer (CK_ATTRIBUTE_PTR attr)
+{
+	return attr->pValue != NULL &&
+	       attr->ulValueLen > 0 &&
+	       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 gint
+trust_ulong_to_level_enum (CK_ULONG trust)
+{
+	switch (trust) {
+	case CKT_NETSCAPE_TRUST_UNKNOWN:
+		return TRUST_UNKNOWN;
+	case CKT_NETSCAPE_UNTRUSTED:
+		return TRUST_UNTRUSTED;
+	case CKT_NETSCAPE_TRUSTED_DELEGATOR:
+		return TRUST_TRUSTED_DELEGATOR;
+	case CKT_NETSCAPE_TRUSTED:
+		return TRUST_TRUSTED;
+	case CKT_NETSCAPE_MUST_VERIFY:
+		return TRUST_MUST_VERIFY;
+	default:
+		return -1;
+	};
+}
+
+static CK_ULONG
+level_enum_to_trust_ulong (guint level)
+{
+	switch (level) {
+	case TRUST_UNKNOWN:
+		return CKT_NETSCAPE_TRUST_UNKNOWN;
+	case TRUST_UNTRUSTED:
+		return CKT_NETSCAPE_UNTRUSTED;
+	case TRUST_TRUSTED_DELEGATOR:
+		return CKT_NETSCAPE_TRUSTED_DELEGATOR;
+	case TRUST_TRUSTED:
+		return CKT_NETSCAPE_TRUSTED;
+	case TRUST_MUST_VERIFY:
+		return CKT_NETSCAPE_MUST_VERIFY;
+	default:
+		return (CK_ULONG)-1;
+	};
+}
+
+static GkmObject*
+factory_create_trust (GkmSession *session, GkmTransaction *transaction,
+                      CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	GkmXdgTrust *trust;
+	CK_ATTRIBUTE_PTR serial, issuer, subject;
+	CK_ATTRIBUTE_PTR md5, sha1;
+	GNode *asn;
+
+	g_return_val_if_fail (attrs || !n_attrs, NULL);
+
+	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 (serial == NULL || issuer == NULL) {
+		gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+		return NULL;
+	}
+
+	if (!validate_der (issuer) || (subject && !validate_der (subject))) {
+		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+		return NULL;
+	}
+
+	if (!validate_integer (serial)) {
+		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+		return NULL;
+	}
+
+	md5 = gkm_attributes_find (attrs, n_attrs, CKA_CERT_MD5_HASH);
+	sha1 = gkm_attributes_find (attrs, n_attrs, CKA_CERT_SHA1_HASH);
+
+	if ((md5 && !validate_hash (md5, G_CHECKSUM_MD5)) ||
+	    (sha1 && !validate_hash (sha1, G_CHECKSUM_SHA1))) {
+		gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+		return NULL;
+	}
+
+	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", "serial", 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", "issuer", NULL),
+		                           g_memdup (subject->pValue, issuer->ulValueLen),
+		                           issuer->ulValueLen, g_free);
+
+	if (md5)
+		append_reference_hash (asn, OID_HASH_MD5, md5);
+	if (sha1)
+		append_reference_hash (asn, OID_HASH_SHA1, sha1);
+
+	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;
+
+	gkm_attributes_consume (attrs, n_attrs, CKA_CERT_MD5_HASH, CKA_CERT_SHA1_HASH,
+	                        CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER, G_MAXULONG);
+
+	gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (trust),
+	                                      TRUE, attrs, n_attrs);
+	return GKM_OBJECT (trust);
+}
+
+static gboolean
+load_trust_pairs (GHashTable *pairs, GNode *asn)
+{
+	GNode *pair;
+	guint count, i;
+	gulong level;
+	gulong trust;
+	GQuark oid;
+
+	g_assert (pairs);
+	g_assert (asn);
+
+	g_hash_table_remove_all (pairs);
+
+	count = egg_asn1x_count (egg_asn1x_node (asn, "trusts", NULL));
+
+	for (i = 0; i < count; ++i) {
+		pair = egg_asn1x_node (asn, "trusts", i + 1, NULL);
+		g_return_val_if_fail (pair, FALSE);
+
+		/* Get the usage */
+		if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (pair, "level", NULL), &level))
+			g_return_val_if_reached (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;
+		}
+
+		/* A key usage */
+		oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (pair, "purpose", NULL));
+		g_return_val_if_fail (oid, FALSE);
+
+		g_hash_table_replace (pairs, GUINT_TO_POINTER (oid),
+		                      gkm_util_ulong_alloc (trust));
+	}
+
+	return TRUE;
+}
+
+static gboolean
+save_trust_pairs (GHashTable *pairs, GNode *asn)
+{
+	GHashTableIter iter;
+	GNode *pair, *node;
+	gpointer key, value;
+	gulong level;
+	GQuark oid;
+
+	g_assert (pairs);
+	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));
+
+		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_integer_as_ulong (egg_asn1x_node (pair, "level", NULL), level);
+	}
+
+	return TRUE;
+}
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gkm_xdg_trust_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
+{
+	GkmXdgTrust *self = GKM_XDG_TRUST (base);
+
+	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);
+
+	/* 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);
+
+	/* Various trust flags */
+	case CKA_TRUST_SERVER_AUTH:
+		return trust_get_usage (self, OID_PURPOSE_SERVER_AUTH, attr);
+	case CKA_TRUST_CLIENT_AUTH:
+		return trust_get_usage (self, OID_PURPOSE_CLIENT_AUTH, attr);
+	case CKA_TRUST_CODE_SIGNING:
+		return trust_get_usage (self, OID_PURPOSE_CODE_SIGNING, attr);
+	case CKA_TRUST_EMAIL_PROTECTION:
+		return trust_get_usage (self, OID_PURPOSE_EMAIL, attr);
+	case CKA_TRUST_IPSEC_END_SYSTEM:
+		return trust_get_usage (self, OID_PURPOSE_IPSEC_ENDPOINT, attr);
+	case CKA_TRUST_IPSEC_TUNNEL:
+		return trust_get_usage (self, OID_PURPOSE_IPSEC_TUNNEL, attr);
+	case CKA_TRUST_IPSEC_USER:
+		return trust_get_usage (self, OID_PURPOSE_IPSEC_USER, attr);
+	case CKA_TRUST_TIME_STAMPING:
+		return trust_get_usage (self, OID_PURPOSE_TIME_STAMPING, attr);
+
+	/* Certificate reference values */
+	case CKA_SUBJECT:
+		return trust_get_der (self, "subject", attr);
+	case CKA_SERIAL_NUMBER:
+		return trust_get_der (self, "serialNumber", attr);
+	case CKA_ISSUER:
+		return trust_get_integer (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);
+
+	default:
+		break;
+	};
+
+	return GKM_OBJECT_CLASS (gkm_xdg_trust_parent_class)->get_attribute (base, session, attr);
+}
+
+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);
+}
+
+static void
+gkm_xdg_trust_finalize (GObject *obj)
+{
+	GkmXdgTrust *self = GKM_XDG_TRUST (obj);
+
+	if (self->pv->asn)
+		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;
+
+	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;
+	gkm_class->set_attribute = gkm_xdg_trust_set_attribute;
+
+	g_type_class_add_private (klass, sizeof (GkmXdgTrustPrivate));
+
+	init_quarks ();
+}
+
+static gboolean
+gkm_xdg_trust_real_load (GkmSerializable *base, GkmSecret *login, gconstpointer data, gsize n_data)
+{
+	GkmXdgTrust *self = GKM_XDG_TRUST (base);
+	GNode *asn = NULL;
+	gpointer copy;
+
+	g_return_val_if_fail (GKM_XDG_IS_TRUST (self), FALSE);
+	g_return_val_if_fail (data, FALSE);
+	g_return_val_if_fail (n_data, FALSE);
+
+	copy = g_memdup (data, n_data);
+
+	asn = egg_asn1x_create_and_decode (xdg_asn1_tab, "trust-1", copy, n_data);
+	if (asn == NULL) {
+		g_warning ("couldn't parse trust data");
+		g_free (copy);
+		return FALSE;
+	}
+
+	/* Next parse out all the pairs */
+	if (!load_trust_pairs (self->pv->pairs, asn)) {
+		egg_asn1x_destroy (asn);
+		g_free (copy);
+		return FALSE;
+	}
+
+	/* Take ownership of this new data */
+	g_free (self->pv->data);
+	self->pv->data = copy;
+	self->pv->n_data = n_data;
+	egg_asn1x_destroy (self->pv->asn);
+	self->pv->asn = asn;
+
+	return TRUE;
+}
+
+static gboolean
+gkm_xdg_trust_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data, gsize *n_data)
+{
+	GkmXdgTrust *self = GKM_XDG_TRUST (base);
+
+	g_return_val_if_fail (GKM_XDG_IS_TRUST (self), FALSE);
+	g_return_val_if_fail (data, FALSE);
+	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))
+		return FALSE;
+
+	*data = egg_asn1x_encode (self->pv->asn, NULL, n_data);
+	if (*data == NULL) {
+		g_warning ("encoding trust failed: %s", egg_asn1x_message (self->pv->asn));
+		return FALSE;
+	}
+
+	/* ASN.1 now refers to this data, take ownership */
+	g_free (self->pv->data);
+	self->pv->data = *data;
+	self->pv->n_data = *n_data;
+
+	/* Return a duplicate, since we own encoded */
+	*data = g_memdup (*data, *n_data);
+	return TRUE;
+}
+
+static void
+gkm_xdg_trust_serializable (GkmSerializableIface *iface)
+{
+	iface->extension = ".trust";
+	iface->load = gkm_xdg_trust_real_load;
+	iface->save = gkm_xdg_trust_real_save;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+
+GkmFactory*
+gkm_xdg_trust_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_NETSCAPE_TRUST;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+	};
+
+	static GkmFactory factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		factory_create_trust
+	};
+
+	return &factory;
+}
diff --git a/pkcs11/xdg-store/gkm-xdg-trust.h b/pkcs11/xdg-store/gkm-xdg-trust.h
new file mode 100644
index 0000000..2780d2e
--- /dev/null
+++ b/pkcs11/xdg-store/gkm-xdg-trust.h
@@ -0,0 +1,54 @@
+/*
+ * 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_H__
+#define __GKM_XDG_TRUST_H__
+
+#include <glib-object.h>
+
+#include "gkm/gkm-object.h"
+
+#define GKM_XDG_FACTORY_TRUST            (gkm_xdg_trust_get_factory ())
+#define GKM_XDG_TYPE_TRUST               (gkm_xdg_trust_get_type ())
+#define GKM_XDG_TRUST(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_XDG_TYPE_TRUST, GkmXdgTrust))
+#define GKM_XDG_TRUST_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_XDG_TYPE_TRUST, GkmXdgTrustClass))
+#define GKM_XDG_IS_TRUST(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_XDG_TYPE_TRUST))
+#define GKM_XDG_IS_TRUST_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_XDG_TYPE_TRUST))
+#define GKM_XDG_TRUST_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_XDG_TYPE_TRUST, GkmXdgTrustClass))
+
+typedef struct _GkmXdgTrust GkmXdgTrust;
+typedef struct _GkmXdgTrustClass GkmXdgTrustClass;
+typedef struct _GkmXdgTrustPrivate GkmXdgTrustPrivate;
+
+struct _GkmXdgTrust {
+	GkmObject parent;
+	GkmXdgTrustPrivate *pv;
+};
+
+struct _GkmXdgTrustClass {
+	GkmObjectClass parent_class;
+};
+
+GType                 gkm_xdg_trust_get_type               (void);
+
+GkmFactory*           gkm_xdg_trust_get_factory            (void);
+
+#endif /* __GKM_XDG_TRUST_H__ */
diff --git a/pkcs11/xdg-store/tests/Makefile.am b/pkcs11/xdg-store/tests/Makefile.am
new file mode 100644
index 0000000..7bf4e78
--- /dev/null
+++ b/pkcs11/xdg-store/tests/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+	p11-tests.conf
diff --git a/pkcs11/xdg-store/tests/p11-tests.conf b/pkcs11/xdg-store/tests/p11-tests.conf
new file mode 100644
index 0000000..fda5f0d
--- /dev/null
+++ b/pkcs11/xdg-store/tests/p11-tests.conf
@@ -0,0 +1,2 @@
+# Configuration for running p11-tests on this module
+init-string = directory='test-data'
diff --git a/pkcs11/xdg-store/xdg.asn b/pkcs11/xdg-store/xdg.asn
new file mode 100644
index 0000000..941a8e9
--- /dev/null
+++ b/pkcs11/xdg-store/xdg.asn
@@ -0,0 +1,47 @@
+XDG { }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- This file contains definitions for keyring
+
+TrustDigest ::= SEQUENCE {
+	algorithm               OBJECT IDENTIFIER,
+	digest                  OCTET STRING
+}
+
+TrustDigests ::= SEQUENCE OF TrustDigest
+
+TrustLevel ::= ENUMERATED {
+	trustUnknown         (0),
+	untrustedUsage       (1),
+	mustVerify           (2),
+	trustedUsage         (3),
+	trustedDelegator     (4)
+}
+
+TrustPair ::= SEQUENCE {
+	purpose                 OBJECT IDENTIFIER,
+	level                   TrustLevel
+}
+
+TrustPairs ::= SEQUENCE OF TrustPair
+
+CertReference ::= SEQUENCE {
+	serialNumber            INTEGER,
+	issuer                  ANY,
+	subject                 ANY OPTIONAL,
+	digests                 TrustDigests
+}
+
+TrustReference ::= CHOICE {
+	certReference CertReference
+}
+
+trust-1 ::= SEQUENCE {
+	reference               TrustReference,
+	trusts                  TrustPairs
+}
+
+END



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