summaryrefslogtreecommitdiff
path: root/pkcs11/xdg-store
diff options
context:
space:
mode:
Diffstat (limited to 'pkcs11/xdg-store')
-rw-r--r--pkcs11/xdg-store/Makefile.am61
-rw-r--r--pkcs11/xdg-store/asn1-def-xdg.c37
-rw-r--r--pkcs11/xdg-store/gkm-xdg-module.c305
-rw-r--r--pkcs11/xdg-store/gkm-xdg-module.h45
-rw-r--r--pkcs11/xdg-store/gkm-xdg-standalone.c51
-rw-r--r--pkcs11/xdg-store/gkm-xdg-store.h29
-rw-r--r--pkcs11/xdg-store/gkm-xdg-trust.c740
-rw-r--r--pkcs11/xdg-store/gkm-xdg-trust.h54
-rw-r--r--pkcs11/xdg-store/tests/Makefile.am2
-rw-r--r--pkcs11/xdg-store/tests/p11-tests.conf2
-rw-r--r--pkcs11/xdg-store/xdg.asn47
11 files changed, 1373 insertions, 0 deletions
diff --git a/pkcs11/xdg-store/Makefile.am b/pkcs11/xdg-store/Makefile.am
new file mode 100644
index 00000000..dfa5f3c0
--- /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 00000000..1d608be6
--- /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 00000000..1e7d81dc
--- /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 00000000..755fa6f2
--- /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 00000000..a539938c
--- /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 00000000..7943a9c2
--- /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 00000000..89235d1c
--- /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 00000000..2780d2e7
--- /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 00000000..7bf4e783
--- /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 00000000..fda5f0dd
--- /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 00000000..941a8e95
--- /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