[glib-networking/tls-database: 5/7] pkcs11: Initial implementation of PKCS#11 GTlsDatabase functionality.



commit def9df9da064736cd1443e5ebc57d8e3e58c8707
Author: Stef Walter <stefw collabora co uk>
Date:   Mon Dec 27 17:24:46 2010 -0600

    pkcs11: Initial implementation of PKCS#11 GTlsDatabase functionality.
    
     * PKCS#11 URI parser.
     * GPkcs11Slot object for each slot.
     * Code for loading pkcs11 modules and searching for objects.

 tls/gnutls/Makefile.am                 |    8 +-
 tls/gnutls/gtlspkcs11database-gnutls.c |  506 ++++++++++++++++++++++++++++++++
 tls/gnutls/gtlspkcs11database-gnutls.h |   52 ++++
 tls/pkcs11/Makefile.am                 |    4 +
 tls/pkcs11/gpkcs11array.c              |    5 +-
 tls/pkcs11/gpkcs11array.h              |    5 +-
 tls/pkcs11/gpkcs11slot.c               |  402 +++++++++++++++++++++++++
 tls/pkcs11/gpkcs11slot.h               |   76 +++++
 tls/pkcs11/gpkcs11uri.c                |  189 ++++++++++++
 tls/pkcs11/gpkcs11uri.h                |   36 +++
 tls/pkcs11/gpkcs11util.h               |   41 +++
 tls/pkcs11/pkcs11-trust-assertions.h   |   56 ++++
 12 files changed, 1377 insertions(+), 3 deletions(-)
---
diff --git a/tls/gnutls/Makefile.am b/tls/gnutls/Makefile.am
index f9f1965..268fc0b 100644
--- a/tls/gnutls/Makefile.am
+++ b/tls/gnutls/Makefile.am
@@ -36,6 +36,8 @@ libgiognutls_la_SOURCES = 		\
 	gtlsinputstream-gnutls.h	\
 	gtlsoutputstream-gnutls.c	\
 	gtlsoutputstream-gnutls.h	\
+	gtlspkcs11database-gnutls.c	\
+	gtlspkcs11database-gnutls.h	\
 	gtlsserverconnection-gnutls.c	\
 	gtlsserverconnection-gnutls.h	\
 	$(NULL)
@@ -48,10 +50,14 @@ libgiognutls_la_CFLAGS = \
 	$(LIBGNUTLS_CFLAGS)		\
 	$(LIBGCRYPT_CFLAGS)		\
 	-DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\"	\
-	-DG_DISABLE_DEPRECATED
+	-DG_DISABLE_DEPRECATED		\
+	-I$(top_srcdir)/tls/		\
+	-DPKCS11_REGISTRY_DIR=\"$(libdir)/pkcs11\" \
+	$(NULL)
 
 libgiognutls_la_LDFLAGS = $(module_flags)
 libgiognutls_la_LIBADD =		\
+	$(top_srcdir)/tls/pkcs11/libgiopkcs11.la \
 	$(GLIB_LIBS)			\
 	$(GNUTLS_LIBS)			\
 	$(LIBGCRYPT_LIBS)		\
diff --git a/tls/gnutls/gtlspkcs11database-gnutls.c b/tls/gnutls/gtlspkcs11database-gnutls.c
new file mode 100644
index 0000000..b60a9a2
--- /dev/null
+++ b/tls/gnutls/gtlspkcs11database-gnutls.c
@@ -0,0 +1,506 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2010 Collabora, Ltd
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#include "config.h"
+
+#include "gtlspkcs11database-gnutls.h"
+
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+#include <gnutls/x509.h>
+
+#include "pkcs11/gpkcs11slot.h"
+#include "pkcs11/gpkcs11util.h"
+#include "pkcs11/pkcs11.h"
+#include "pkcs11/pkcs11-trust-assertions.h"
+
+static void g_tls_pkcs11_database_gnutls_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsPkcs11DatabaseGnutls, g_tls_pkcs11_database_gnutls,
+                         G_TYPE_TLS_DATABASE_GNUTLS,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_pkcs11_database_gnutls_initable_iface_init));
+
+struct _GTlsPkcs11DatabaseGnutlsPrivate
+{
+  /* no changes after construction */
+  GList *pkcs11_slots;
+  GList *modules;
+  GList *initialized;
+};
+
+static CK_RV
+create_mutex (void **mutex)
+{
+  if (!mutex)
+    return CKR_ARGUMENTS_BAD;
+
+  if (!g_thread_supported ())
+    {
+      g_warning ("cannot create pkcs11 mutex, threading has not been initialized");
+      return CKR_GENERAL_ERROR;
+    }
+
+  *mutex = g_mutex_new ();
+  return CKR_OK;
+}
+
+static CK_RV
+destroy_mutex (void *mutex)
+{
+  if (!mutex)
+    return CKR_MUTEX_BAD;
+  g_mutex_free ((GMutex*)mutex);
+  return CKR_OK;
+}
+
+static CK_RV
+lock_mutex (void *mutex)
+{
+  if (!mutex)
+    return CKR_MUTEX_BAD;
+  g_mutex_lock ((GMutex*)mutex);
+  return CKR_OK;
+}
+
+static CK_RV
+unlock_mutex (void *mutex)
+{
+  if (!mutex)
+    return CKR_MUTEX_BAD;
+  g_mutex_unlock ((GMutex*)mutex);
+  return CKR_OK;
+}
+
+static gchar**
+list_registered_pkcs11_module_paths (const gchar *directory, GError **error)
+{
+  const gchar *name;
+  GError *err = NULL;
+  GArray *paths;
+  GDir *dir;
+  gchar *path;
+
+  paths = g_array_new (TRUE, TRUE, sizeof (gchar*));
+  dir = g_dir_open (directory, 0, &err);
+
+  if (dir == NULL)
+    {
+      if (g_error_matches (err, G_FILE_ERROR, G_FILE_ERROR_NOENT) ||
+          g_error_matches (err, G_FILE_ERROR, G_FILE_ERROR_NOTDIR))
+        {
+          g_clear_error (&err);
+          return (gchar**)g_array_free (paths, FALSE);
+        }
+      else
+        {
+          g_array_free (paths, TRUE);
+          g_propagate_error (error, err);
+          return NULL;
+        }
+    }
+
+  for (;;)
+    {
+      name = g_dir_read_name (dir);
+      if (!name)
+        break;
+
+      /* libtool can bite my shiny metal ass */
+      if (g_str_has_suffix (name, ".la"))
+        continue;
+
+      path = g_build_filename (directory, name, NULL);
+      if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
+        g_array_append_val (paths, path);
+      else
+        g_free (path);
+    }
+
+  g_dir_close (dir);
+
+  return (gchar**)g_array_free (paths, FALSE);
+}
+
+static CK_FUNCTION_LIST_PTR
+load_and_initialize_module (GTlsPkcs11DatabaseGnutls   *self,
+                            const gchar                *path,
+                            GError                    **error)
+{
+  CK_C_GetFunctionList get_function_list;
+  CK_C_INITIALIZE_ARGS init_args;
+  CK_FUNCTION_LIST_PTR funcs;
+  GModule *module;
+  CK_RV rv;
+
+  /* Load the actual module */
+  module = g_module_open (path, 0);
+  if (!module)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   "Error loading PKCS#11 module: %s", g_module_error ());
+      return NULL;
+    }
+
+  /* Get the entry point */
+  if (!g_module_symbol (module, "C_GetFunctionList", (void**)&get_function_list))
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   "Invalid PKCS#11 module: %s", g_module_error ());
+      g_module_close (module);
+      return NULL;
+    }
+
+  /* Get the function list */
+  rv = (get_function_list) (&funcs);
+  if (rv != CKR_OK)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   "Couldn't get PKCS#11 function list: %s",
+                   g_pkcs11_rv_to_message (rv));
+      g_module_close (module);
+      return NULL;
+    }
+
+  memset (&init_args, 0, sizeof (init_args));
+  init_args.flags = CKF_OS_LOCKING_OK;
+  init_args.CreateMutex = create_mutex;
+  init_args.DestroyMutex = destroy_mutex;
+  init_args.LockMutex = lock_mutex;
+  init_args.UnlockMutex = unlock_mutex;
+  init_args.pReserved = NULL;
+
+  /* Now initialize the module */
+  rv = (funcs->C_Initialize) (&init_args);
+  if (rv == CKR_OK)
+    self->priv->initialized = g_list_append (self->priv->initialized, funcs);
+  if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
+    rv = CKR_OK;
+
+  if (rv == CKR_OK)
+    {
+      self->priv->modules = g_list_append (self->priv->modules, module);
+      return funcs;
+    }
+  else
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   "Couldn't initialize PKCS#11 module: %s",
+                   g_pkcs11_rv_to_message (rv));
+      g_module_close (module);
+      return NULL;
+    }
+}
+
+static gboolean
+enumerate_and_setup_slots (GTlsPkcs11DatabaseGnutls   *self,
+                           CK_FUNCTION_LIST_PTR        funcs,
+                           GError                    **error)
+{
+  CK_ULONG i, count = 0;
+  CK_SLOT_ID *list;
+  GPkcs11Slot *slot;
+  CK_RV rv;
+
+  rv = (funcs->C_GetSlotList) (CK_FALSE, NULL, &count);
+  if (rv != CKR_OK)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   "Couldn't load list of slots in PKCS#11 module: %s",
+                   g_pkcs11_rv_to_message (rv));
+      return FALSE;
+    }
+
+  if (count == 0)
+    return TRUE;
+
+  list = g_new0 (CK_SLOT_ID, count);
+  rv = (funcs->C_GetSlotList) (CK_FALSE, list, &count);
+  if (rv != CKR_OK)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   "Couldn't load list of slots in PKCS#11 module: %s",
+                   g_pkcs11_rv_to_message (rv));
+      g_free (list);
+      return FALSE;
+    }
+
+  for (i = 0; i < count; ++i)
+    {
+      slot = g_object_new (G_TYPE_PKCS11_SLOT,
+                           "slot-id", list[i],
+                           "module", funcs,
+                           NULL);
+      self->priv->pkcs11_slots = g_list_append (self->priv->pkcs11_slots, slot);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+find_objects_on_all_slots (GTlsPkcs11DatabaseGnutls *self,
+                           GPkcs11Array            *match,
+                           CK_ATTRIBUTE_TYPE       *attr_types,
+                           guint                    attr_types_length,
+                           GPkcs11SlotFindFunc     callback,
+                           gpointer                 user_data,
+                           GError                 **error)
+{
+  GList *l;
+  GPkcs11SlotFindStatus status;
+
+  for (l = self->priv->pkcs11_slots; l; l = g_list_next (l))
+    {
+      status = g_pkcs11_slot_find_objects (l->data, match, attr_types,
+                                           attr_types_length, callback,
+                                           user_data, error);
+      if (status != G_PKCS11_SLOT_FIND_COMPLETED)
+        break;
+    }
+
+  return status != G_PKCS11_SLOT_FIND_FAILED;
+}
+
+static gboolean
+find_if_any_exist (GPkcs11Slot       *slot,
+                   CK_OBJECT_HANDLE   object,
+                   GPkcs11Array      *attributes,
+                   gpointer           user_data)
+{
+  gboolean *found = (gboolean*)user_data;
+  *found = TRUE;
+  return TRUE; /* stop iteration */
+}
+
+static gboolean
+find_first_certificate (GPkcs11Slot       *slot,
+                        CK_OBJECT_HANDLE   object,
+                        GPkcs11Array      *attributes,
+                        gpointer           user_data)
+{
+  GTlsCertificate **issuer = (GTlsCertificate**)user_data;
+  const CK_ATTRIBUTE *attr;
+  gnutls_datum_t datum;
+
+  attr = g_pkcs11_array_find_valid (attributes, CKA_VALUE);
+  if (attr == NULL)
+    return FALSE; /* continue */
+
+  datum.data = attr->pValue;
+  datum.size = attr->ulValueLen;
+
+  *issuer = g_tls_certificate_gnutls_new (&datum, NULL);
+  return TRUE; /* stop iteration */
+}
+
+static const gchar*
+calculate_peer_for_identity (GSocketConnectable *identity)
+{
+  const char *peer;
+
+  if (G_IS_NETWORK_ADDRESS (identity))
+    peer = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
+  else if (G_IS_NETWORK_SERVICE (identity))
+    peer = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
+  else
+    peer = NULL;
+
+  return peer;
+}
+
+static void
+g_tls_pkcs11_database_gnutls_finalize (GObject *object)
+{
+  GTlsPkcs11DatabaseGnutls *self = G_TLS_PKCS11_DATABASE_GNUTLS (object);
+  GList *l;
+
+  for (l = self->priv->pkcs11_slots; l; l = g_list_next (l))
+    g_object_unref (l->data);
+  g_list_free (self->priv->pkcs11_slots);
+  self->priv->pkcs11_slots = NULL;
+
+  G_OBJECT_CLASS (g_tls_pkcs11_database_gnutls_parent_class)->finalize (object);
+}
+
+static void
+g_tls_pkcs11_database_gnutls_init (GTlsPkcs11DatabaseGnutls *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                            G_TYPE_TLS_PKCS11_DATABASE_GNUTLS,
+                                            GTlsPkcs11DatabaseGnutlsPrivate);
+}
+
+static gboolean
+g_tls_pkcs11_database_gnutls_lookup_assertion (GTlsDatabaseGnutls          *database,
+                                               GTlsCertificateGnutls       *certificate,
+                                               GTlsDatabaseGnutlsAssertion  assertion,
+                                               GSocketConnectable          *identity,
+                                               GCancellable                *cancellable,
+                                               GError                     **error)
+{
+  GTlsPkcs11DatabaseGnutls *self = G_TLS_PKCS11_DATABASE_GNUTLS (database);
+  GByteArray *der = NULL;
+  gboolean found, ready;
+  GPkcs11Array *match;
+  const gchar *peer;
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (certificate), FALSE);
+  g_return_val_if_fail (!identity || G_IS_SOCKET_CONNECTABLE (identity), FALSE);
+  g_return_val_if_fail (!error || !*error, FALSE);
+
+  ready = FALSE;
+  found = FALSE;
+  match = g_pkcs11_array_new ();
+
+  if (assertion == G_TLS_DATABASE_GNUTLS_ANCHORED_CERTIFICATE ||
+      assertion == G_TLS_DATABASE_GNUTLS_PINNED_CERTIFICATE)
+    {
+      g_object_get (certificate, "certificate", &der, NULL);
+      g_return_val_if_fail (der, FALSE);
+      g_pkcs11_array_add_value (match, CKA_X_CERTIFICATE_VALUE, der->data, der->len);
+      g_byte_array_unref (der);
+
+      /* TLS Server Authentication */
+      g_pkcs11_array_add_value (match, CKA_X_PURPOSE, "1.3.6.1.5.5.7.3.1", -1);
+
+      if (assertion == G_TLS_DATABASE_GNUTLS_ANCHORED_CERTIFICATE)
+        {
+          g_pkcs11_array_add_ulong (match, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE);
+          ready = TRUE;
+        }
+      else if (assertion == G_TLS_DATABASE_GNUTLS_PINNED_CERTIFICATE)
+        {
+          g_pkcs11_array_add_ulong (match, CKA_X_ASSERTION_TYPE, CKT_X_PINNED_CERTIFICATE);
+          peer = calculate_peer_for_identity (identity);
+          if (peer)
+            {
+              g_pkcs11_array_add_value (match, CKA_X_PEER, peer, -1);
+              ready = TRUE;
+            }
+        }
+    }
+
+  if (ready)
+    find_objects_on_all_slots (self, match, NULL, 0, find_if_any_exist,
+                               &found, error);
+
+  g_pkcs11_array_unref (match);
+  return found;
+}
+
+static GTlsCertificate*
+g_tls_pkcs11_database_gnutls_lookup_issuer (GTlsDatabase          *database,
+                                            GTlsCertificate       *certificate,
+                                            GCancellable          *cancellable,
+                                            GError               **error)
+{
+  GTlsPkcs11DatabaseGnutls *self = G_TLS_PKCS11_DATABASE_GNUTLS (database);
+  GTlsCertificate *issuer = NULL;
+  GPkcs11Array *match = NULL;
+  CK_ATTRIBUTE_TYPE attr_type = CKA_VALUE;
+  gnutls_x509_crt_t cert;
+  gnutls_datum_t dn;
+  int gerr;
+
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (certificate), NULL);
+
+  /* Dig out the issuer of this certificate */
+  cert = g_tls_certificate_gnutls_get_cert (G_TLS_CERTIFICATE_GNUTLS (certificate));
+  gerr = gnutls_x509_crt_get_raw_issuer_dn (cert, &dn);
+  if (gerr < 0)
+    {
+      g_warning ("failed to get issuer of certificate: %s", gnutls_strerror (gerr));
+      return NULL;
+    }
+
+  match = g_pkcs11_array_new ();
+  g_pkcs11_array_add_value (match, CKA_SUBJECT, dn.data, dn.size);
+  gnutls_free (dn.data);
+
+  find_objects_on_all_slots (self, match, &attr_type, 1,
+                             find_first_certificate, &issuer, error);
+
+  g_pkcs11_array_unref (match);
+  return issuer;
+}
+
+static void
+g_tls_pkcs11_database_gnutls_class_init (GTlsPkcs11DatabaseGnutlsClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
+  GTlsDatabaseGnutlsClass *gnutls_class = G_TLS_DATABASE_GNUTLS_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsPkcs11DatabaseGnutlsPrivate));
+
+  gobject_class->finalize     = g_tls_pkcs11_database_gnutls_finalize;
+
+  database_class->lookup_issuer = g_tls_pkcs11_database_gnutls_lookup_issuer;
+  gnutls_class->lookup_assertion = g_tls_pkcs11_database_gnutls_lookup_assertion;
+}
+
+static gboolean
+g_tls_pkcs11_database_gnutls_initable_init (GInitable     *initable,
+                                            GCancellable  *cancellable,
+                                            GError       **error)
+{
+  GTlsPkcs11DatabaseGnutls *self = G_TLS_PKCS11_DATABASE_GNUTLS (initable);
+  CK_FUNCTION_LIST_PTR funcs;
+  gchar **paths, **path;
+  GError *err = NULL;
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (!error || !*error, FALSE);
+
+  paths = list_registered_pkcs11_module_paths (PKCS11_REGISTRY_DIR, &err);
+  if (!paths)
+    {
+      if (err)
+        {
+          g_propagate_error (error, err);
+          return FALSE;
+        }
+      return TRUE;
+    }
+
+  /* TODO: Partial success or failure? */
+
+  for (path = paths; *path; ++path)
+    {
+      funcs = load_and_initialize_module (self, *path, error);
+      if (funcs != NULL)
+        {
+          if (enumerate_and_setup_slots (self, funcs, error))
+            ret = TRUE;
+        }
+    }
+
+  g_strfreev (paths);
+  return ret;
+}
+
+static void
+g_tls_pkcs11_database_gnutls_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = g_tls_pkcs11_database_gnutls_initable_init;
+}
diff --git a/tls/gnutls/gtlspkcs11database-gnutls.h b/tls/gnutls/gtlspkcs11database-gnutls.h
new file mode 100644
index 0000000..bc3771c
--- /dev/null
+++ b/tls/gnutls/gtlspkcs11database-gnutls.h
@@ -0,0 +1,52 @@
+/* GIO - GLib Certificate, Output and Gnutlsing Library
+ *
+ * Copyright © 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#ifndef __G_TLS_PKCS11_DATABASE_GNUTLS_H__
+#define __G_TLS_PKCS11_DATABASE_GNUTLS_H__
+
+#include <gio/gio.h>
+
+#include "gtlsdatabase-gnutls.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_PKCS11_DATABASE_GNUTLS            (g_tls_pkcs11_database_gnutls_get_type ())
+#define G_TLS_PKCS11_DATABASE_GNUTLS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_PKCS11_DATABASE_GNUTLS, GTlsPkcs11DatabaseGnutls))
+#define G_TLS_PKCS11_DATABASE_GNUTLS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_PKCS11_DATABASE_GNUTLS, GTlsPkcs11DatabaseGnutlsClass))
+#define G_IS_TLS_PKCS11_DATABASE_GNUTLS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_PKCS11_DATABASE_GNUTLS))
+#define G_IS_TLS_PKCS11_DATABASE_GNUTLS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_PKCS11_DATABASE_GNUTLS))
+#define G_TLS_PKCS11_DATABASE_GNUTLS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_PKCS11_DATABASE_GNUTLS, GTlsPkcs11DatabaseGnutlsClass))
+
+typedef struct _GTlsPkcs11DatabaseGnutlsPrivate                   GTlsPkcs11DatabaseGnutlsPrivate;
+typedef struct _GTlsPkcs11DatabaseGnutlsClass                     GTlsPkcs11DatabaseGnutlsClass;
+typedef struct _GTlsPkcs11DatabaseGnutls                          GTlsPkcs11DatabaseGnutls;
+
+struct _GTlsPkcs11DatabaseGnutlsClass
+{
+  GTlsDatabaseGnutlsClass parent_class;
+};
+
+struct _GTlsPkcs11DatabaseGnutls
+{
+  GTlsDatabaseGnutls parent_instance;
+  GTlsPkcs11DatabaseGnutlsPrivate *priv;
+};
+
+GType                        g_tls_pkcs11_database_gnutls_get_type              (void) G_GNUC_CONST;
+
+GTlsDatabase*                g_tls_pkcs11_database_gnutls_new                   (void);
+
+G_END_DECLS
+
+#endif /* __G_TLS_PKCS11_DATABASE_GNUTLS_H___ */
diff --git a/tls/pkcs11/Makefile.am b/tls/pkcs11/Makefile.am
index 802fc15..be8a479 100644
--- a/tls/pkcs11/Makefile.am
+++ b/tls/pkcs11/Makefile.am
@@ -8,6 +8,10 @@ noinst_LTLIBRARIES = \
 libgiopkcs11_la_SOURCES = 		\
 	gpkcs11array.c			\
 	gpkcs11array.h			\
+	gpkcs11slot.c			\
+	gpkcs11slot.h			\
+	gpkcs11uri.c			\
+	gpkcs11uri.h			\
 	pkcs11.h			\
 	$(NULL)
 
diff --git a/tls/pkcs11/gpkcs11array.c b/tls/pkcs11/gpkcs11array.c
index 2b84e4c..0ad2e0e 100644
--- a/tls/pkcs11/gpkcs11array.c
+++ b/tls/pkcs11/gpkcs11array.c
@@ -70,12 +70,15 @@ void
 g_pkcs11_array_add_value (GPkcs11Array      *array,
                           CK_ATTRIBUTE_TYPE  type,
                           gconstpointer      value,
-                          gsize              length)
+                          gssize              length)
 {
   CK_ATTRIBUTE attr;
 
   g_return_if_fail (array);
 
+  if (length < 0)
+    length = strlen (value);
+
   attr.type = type;
   attr.pValue = (gpointer)value;
   attr.ulValueLen = length;
diff --git a/tls/pkcs11/gpkcs11array.h b/tls/pkcs11/gpkcs11array.h
index ef6141c..8ff6a9e 100644
--- a/tls/pkcs11/gpkcs11array.h
+++ b/tls/pkcs11/gpkcs11array.h
@@ -44,7 +44,7 @@ void                g_pkcs11_array_add                      (GPkcs11Array
 void                g_pkcs11_array_add_value                (GPkcs11Array        *array,
                                                              CK_ATTRIBUTE_TYPE    type,
                                                              gconstpointer        value,
-                                                             gsize                length);
+                                                             gssize               length);
 
 void                g_pkcs11_array_add_boolean              (GPkcs11Array         *array,
                                                              CK_ATTRIBUTE_TYPE     type,
@@ -57,6 +57,9 @@ void                g_pkcs11_array_add_ulong                (GPkcs11Array
 const CK_ATTRIBUTE* g_pkcs11_array_find                     (GPkcs11Array         *array,
                                                              CK_ATTRIBUTE_TYPE     type);
 
+const CK_ATTRIBUTE* g_pkcs11_array_find_valid               (GPkcs11Array         *array,
+                                                             CK_ATTRIBUTE_TYPE     type);
+
 gboolean            g_pkcs11_array_find_boolean             (GPkcs11Array         *array,
                                                              CK_ATTRIBUTE_TYPE     type,
                                                              gboolean             *value);
diff --git a/tls/pkcs11/gpkcs11slot.c b/tls/pkcs11/gpkcs11slot.c
new file mode 100644
index 0000000..43e7cc1
--- /dev/null
+++ b/tls/pkcs11/gpkcs11slot.c
@@ -0,0 +1,402 @@
+/* GIO - Small GLib wrapper of PKCS#11 for use in GTls
+ *
+ * Copyright © 2010 Collabora, Ltd
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#include "config.h"
+
+#include "gpkcs11slot.h"
+
+#include "gpkcs11array.h"
+#include "gpkcs11util.h"
+
+#include <glib/gi18n.h>
+
+enum {
+  PROP_0,
+  PROP_MODULE,
+  PROP_SLOT_ID
+};
+
+struct _GPkcs11SlotPrivate
+{
+  /* read-only after construct */
+  CK_FUNCTION_LIST_PTR module;
+  CK_SLOT_ID slot_id;
+
+  /* protected by mutex */
+  GMutex *mutex;
+  CK_SESSION_HANDLE last_session;
+};
+
+G_DEFINE_TYPE (GPkcs11Slot, g_pkcs11_slot, G_TYPE_OBJECT);
+
+static CK_SESSION_HANDLE
+session_checkout_or_open (GPkcs11Slot  *self,
+                          GError       **error)
+{
+  CK_SESSION_HANDLE session = 0;
+  CK_RV rv;
+
+  g_mutex_lock (self->priv->mutex);
+
+  if (self->priv->last_session)
+    {
+      session = self->priv->last_session;
+      self->priv->last_session = 0;
+    }
+
+  g_mutex_lock (self->priv->mutex);
+
+  if (session)
+    return session;
+
+  rv = (self->priv->module->C_OpenSession) (self->priv->slot_id, CKF_SERIAL_SESSION,
+                                            NULL, NULL, &session);
+  if (rv != CKR_OK)
+    {
+      g_pkcs11_util_propagate_error (error, rv);
+      return 0;
+    }
+
+  return session;
+}
+
+static void
+session_close (GPkcs11Slot       *self,
+               CK_SESSION_HANDLE   session)
+{
+  CK_RV rv;
+
+  g_assert (session != 0);
+
+  rv = (self->priv->module->C_CloseSession) (session);
+  if (rv != CKR_OK)
+    g_warning ("couldn't close pkcs11 session: %s",
+               g_pkcs11_util_rv_to_message (rv));
+}
+
+static void
+session_checkin_or_close (GPkcs11Slot      *self,
+                          CK_SESSION_HANDLE  session)
+{
+  g_assert (session != 0);
+
+  g_mutex_lock (self->priv->mutex);
+
+  if (self->priv->last_session == 0)
+    {
+      self->priv->last_session = session;
+      session = 0;
+    }
+
+  g_mutex_lock (self->priv->mutex);
+
+  if (session != 0)
+    session_close (self, session);
+}
+
+static GPkcs11Array*
+retrieve_object_attributes (GPkcs11Slot       *self,
+                            CK_SESSION_HANDLE   session,
+                            CK_OBJECT_HANDLE    object,
+                            CK_ATTRIBUTE_TYPE  *attr_types,
+                            guint               attr_types_length)
+{
+  GPkcs11Array *result;
+  CK_ATTRIBUTE_PTR attr;
+  CK_ATTRIBUTE blank;
+  CK_RV rv;
+  guint i;
+
+  result = g_pkcs11_array_new ();
+  memset (&blank, 0, sizeof (blank));
+  for (i = 0; i < attr_types_length; ++i)
+    {
+      blank.type = attr_types[i];
+      g_pkcs11_array_add (result, &blank);
+    }
+
+  /* Get all the required buffer sizes */
+  rv = (self->priv->module->C_GetAttributeValue) (session, object,
+                                                  result->attrs, result->len);
+  if (rv != CKR_OK &&
+      rv != CKR_ATTRIBUTE_SENSITIVE &&
+      rv != CKR_ATTRIBUTE_TYPE_INVALID)
+    {
+      g_message ("couldn't read pkcs11 object attributes: %s",
+                 g_pkcs11_util_rv_to_message (rv));
+      g_pkcs11_array_unref (result);
+      return NULL;
+    }
+
+  /* Now allocate memory for them all */
+  for (i = 0; i < attr_types_length; ++i)
+    {
+      attr = &g_pkcs11_array_index (result, i);
+      if (attr->ulValueLen != (CK_ULONG)-1 && attr->ulValueLen)
+          attr->pValue = g_malloc0 (attr->ulValueLen);
+    }
+
+  /* And finally get all the values */
+  rv = (self->priv->module->C_GetAttributeValue) (session, object,
+                                                  result->attrs, result->len);
+  if (rv != CKR_OK &&
+      rv != CKR_ATTRIBUTE_SENSITIVE &&
+      rv != CKR_ATTRIBUTE_TYPE_INVALID &&
+      rv != CKR_BUFFER_TOO_SMALL)
+    {
+      g_message ("couldn't retrieve pkcs11 object attributes: %s",
+                 g_pkcs11_util_rv_to_message (rv));
+      g_pkcs11_array_unref (result);
+      return NULL;
+    }
+
+  return result;
+}
+
+static void
+g_pkcs11_slot_init (GPkcs11Slot *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                            G_TYPE_PKCS11_SLOT,
+                                            GPkcs11SlotPrivate);
+  self->priv->mutex = g_mutex_new ();
+}
+
+static void
+g_pkcs11_slot_dispose (GObject *object)
+{
+  GPkcs11Slot *self = G_PKCS11_SLOT (object);
+  CK_SESSION_HANDLE session = 0;
+
+  g_mutex_lock (self->priv->mutex);
+
+  session = self->priv->last_session;
+  self->priv->last_session = 0;
+
+  g_mutex_unlock (self->priv->mutex);
+
+  if (session)
+    session_close (self, session);
+
+  G_OBJECT_CLASS (g_pkcs11_slot_parent_class)->dispose (object);
+}
+
+static void
+g_pkcs11_slot_finalize (GObject *object)
+{
+  GPkcs11Slot *self = G_PKCS11_SLOT (object);
+
+  g_assert (self->priv->last_session == 0);
+  g_mutex_free (self->priv->mutex);
+  self->priv->mutex = NULL;
+
+  G_OBJECT_CLASS (g_pkcs11_slot_parent_class)->finalize (object);
+}
+
+static void
+g_pkcs11_slot_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  GPkcs11Slot *self = G_PKCS11_SLOT (object);
+
+  switch (prop_id)
+    {
+    case PROP_MODULE:
+      g_value_set_pointer (value, self->priv->module);
+      break;
+
+    case PROP_SLOT_ID:
+      g_value_set_ulong (value, self->priv->slot_id);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_pkcs11_slot_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GPkcs11Slot *self = G_PKCS11_SLOT (object);
+
+  switch (prop_id)
+    {
+    case PROP_MODULE:
+      self->priv->module = g_value_get_pointer (value);
+      g_assert (self->priv->module);
+      break;
+
+    case PROP_SLOT_ID:
+      self->priv->slot_id = g_value_get_ulong (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_pkcs11_slot_class_init (GPkcs11SlotClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GPkcs11SlotPrivate));
+
+  gobject_class->get_property = g_pkcs11_slot_get_property;
+  gobject_class->set_property = g_pkcs11_slot_set_property;
+  gobject_class->dispose      = g_pkcs11_slot_dispose;
+  gobject_class->finalize     = g_pkcs11_slot_finalize;
+
+  g_type_class_add_private (klass, sizeof (GPkcs11SlotPrivate));
+
+  g_object_class_install_property (gobject_class, PROP_MODULE,
+                                   g_param_spec_pointer ("module",
+                                                         N_("Module"),
+                                                         N_("PKCS#11 Module Pointer"),
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SLOT_ID,
+                                   g_param_spec_ulong ("slot-id",
+                                                         N_("Slot ID"),
+                                                         N_("PKCS#11 Slot Identifier"),
+                                                         0,
+                                                         G_MAXULONG,
+                                                         G_MAXULONG,
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+}
+
+gboolean
+g_pkcs11_slot_login (GPkcs11Slot   *self,
+                      const guchar   *pin,
+                      gsize           pin_length,
+                      GError        **error)
+{
+  CK_SESSION_HANDLE session;
+  GError *err = NULL;
+  CK_RV rv;
+
+  g_return_val_if_fail (G_IS_PKCS11_SLOT (self), FALSE);
+  g_return_val_if_fail (!error || !*error, FALSE);
+
+  session = session_checkout_or_open (self, &err);
+  if (err != NULL)
+    {
+      g_propagate_error (error, err);
+      return FALSE;
+    }
+
+  rv = (self->priv->module->C_Login) (session, CKU_USER,
+                                      (CK_BYTE_PTR)pin, pin_length);
+
+  session_checkin_or_close (self, session);
+
+  if (rv != CKR_OK)
+    {
+      g_pkcs11_util_propagate_error (error, rv);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+GPkcs11SlotFindStatus
+g_pkcs11_slot_find_objects (GPkcs11Slot           *self,
+                            GPkcs11Array           *match,
+                            CK_ATTRIBUTE_TYPE      *attr_types,
+                            guint                   attr_types_length,
+                            GPkcs11SlotFindFunc    callback,
+                            gpointer                user_data,
+                            GError                **error)
+{
+  GPkcs11SlotFindStatus status = G_PKCS11_SLOT_FIND_COMPLETED;
+  CK_OBJECT_HANDLE objects[256];
+  CK_SESSION_HANDLE session;
+  GPkcs11Array *attrs;
+  GError *err = NULL;
+  gboolean stop = FALSE;
+  CK_ULONG count, i;
+  CK_RV rv;
+
+  g_return_val_if_fail (G_IS_PKCS11_SLOT (self), FALSE);
+  g_return_val_if_fail (match, FALSE);
+  g_return_val_if_fail (callback, FALSE);
+  g_return_val_if_fail (!error || !*error, FALSE);
+
+  session = session_checkout_or_open (self, &err);
+  if (err != NULL)
+    {
+      g_propagate_error (error, err);
+      return G_PKCS11_SLOT_FIND_FAILED;
+    }
+
+  rv = (self->priv->module->C_FindObjectsInit) (session, match->attrs, match->len);
+
+  while (!stop && rv == CKR_OK)
+    {
+      count = 0;
+      rv = (self->priv->module->C_FindObjects) (session, objects,
+                                                G_N_ELEMENTS (objects), &count);
+      if (rv == CKR_OK)
+        {
+          if (count == 0)
+            break;
+
+          for (i = 0; !stop && i < count; ++i)
+            {
+              if (attr_types_length)
+                attrs = retrieve_object_attributes (self, session, objects[i],
+                                                    attr_types, attr_types_length);
+              else
+                attrs = NULL;
+              stop = (callback) (self, objects[i], attrs, user_data);
+              if (attrs)
+                g_pkcs11_array_unref (attrs);
+            }
+        }
+    }
+
+  if (stop)
+    status = G_PKCS11_SLOT_FIND_STOPPED;
+
+  if (rv != CKR_OK && rv != CKR_TOKEN_NOT_PRESENT)
+    {
+      g_pkcs11_util_propagate_error (error, rv);
+      status = G_PKCS11_SLOT_FIND_FAILED;
+    }
+
+  rv = (self->priv->module->C_FindObjectsFinal) (session);
+  if (rv == CKR_OK)
+    session_close (self, session);
+  else
+    session_checkin_or_close (self, session);
+
+  return status;
+}
diff --git a/tls/pkcs11/gpkcs11slot.h b/tls/pkcs11/gpkcs11slot.h
new file mode 100644
index 0000000..fcc017b
--- /dev/null
+++ b/tls/pkcs11/gpkcs11slot.h
@@ -0,0 +1,76 @@
+/* GIO - Small GLib wrapper of PKCS#11 for use in GTls
+ *
+ * Copyright © 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#ifndef __G_PKCS11_SLOT_H__
+#define __G_PKCS11_SLOT_H__
+
+#include <gio/gio.h>
+
+#include "gpkcs11array.h"
+
+#include "pkcs11.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  G_PKCS11_SLOT_FIND_FAILED,
+  G_PKCS11_SLOT_FIND_STOPPED,
+  G_PKCS11_SLOT_FIND_COMPLETED
+} GPkcs11SlotFindStatus;
+
+#define G_TYPE_PKCS11_SLOT            (g_pkcs11_slot_get_type ())
+#define G_PKCS11_SLOT(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_PKCS11_SLOT, GPkcs11Slot))
+#define G_PKCS11_SLOT_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PKCS11_SLOT, GPkcs11SlotClass))
+#define G_IS_PKCS11_SLOT(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_PKCS11_SLOT))
+#define G_IS_PKCS11_SLOT_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_PKCS11_SLOT))
+#define G_PKCS11_SLOT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_PKCS11_SLOT, GPkcs11SlotClass))
+
+typedef struct _GPkcs11SlotPrivate                   GPkcs11SlotPrivate;
+typedef struct _GPkcs11SlotClass                     GPkcs11SlotClass;
+typedef struct _GPkcs11Slot                          GPkcs11Slot;
+
+struct _GPkcs11SlotClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GPkcs11Slot
+{
+  GObject parent_instance;
+  GPkcs11SlotPrivate *priv;
+};
+
+typedef gboolean             (*GPkcs11SlotFindFunc)           (GPkcs11Slot *slot,
+                                                               CK_OBJECT_HANDLE object,
+                                                               GPkcs11Array *attributes,
+                                                               gpointer user_data);
+
+GType                        g_pkcs11_slot_get_type           (void) G_GNUC_CONST;
+
+gboolean                     g_pkcs11_slot_login              (GPkcs11Slot           *self,
+                                                               const guchar*           pin,
+                                                               gsize                   pin_length,
+                                                               GError                **error);
+
+GPkcs11SlotFindStatus       g_pkcs11_slot_find_objects        (GPkcs11Slot           *self,
+                                                               GPkcs11Array           *match,
+                                                               CK_ATTRIBUTE_TYPE      *attr_types,
+                                                               guint                   attr_types_length,
+                                                               GPkcs11SlotFindFunc    callback,
+                                                               gpointer                user_data,
+                                                               GError                **error);
+
+G_END_DECLS
+
+#endif /* __G_TLS_CERTIFICATE_GNUTLS_H___ */
diff --git a/tls/pkcs11/gpkcs11uri.c b/tls/pkcs11/gpkcs11uri.c
new file mode 100644
index 0000000..2ad8ff5
--- /dev/null
+++ b/tls/pkcs11/gpkcs11uri.c
@@ -0,0 +1,189 @@
+/* GIO - Small GLib wrapper of PKCS#11 for use in GTls
+ *
+ * Copyright © 2010 Collabora, Ltd
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#include "config.h"
+
+#include "gpkcs11uri.h"
+#include "gpkcs11util.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <string.h>
+
+#define URI_PREFIX "pkcs11:"
+#define URI_PREFIX_LENGTH 7
+
+enum {
+  FAILED = -1,
+  NO_MATCH = 0,
+  SUCCESS = 1
+};
+
+static gint
+parse_string_field (const gchar    *name,
+                    const gchar    *start,
+                    const gchar    *end,
+                    CK_INFO        *info,
+                    CK_TOKEN_INFO  *token,
+                    GError        **error)
+{
+  unsigned char *value;
+  gsize value_length;
+  gchar *string;
+  gsize string_length;
+
+  g_assert (name);
+  g_assert (start);
+  g_assert (end);
+  g_assert (token);
+  g_assert (info);
+
+  if (g_str_equal (name, "model"))
+    {
+      value = token->model;
+      value_length = sizeof (token->model);
+    }
+  else if (g_str_equal (name, "manufacturer"))
+    {
+      value = token->manufacturerID;
+      value_length = sizeof (token->manufacturerID);
+    }
+  else if (g_str_equal (name, "serial"))
+    {
+      value = token->serialNumber;
+      value_length = sizeof (token->serialNumber);
+    }
+  else if (g_str_equal (name, "token"))
+    {
+      value = token->label;
+      value_length = sizeof (token->label);
+    }
+  else if (g_str_equal (name, "library-description"))
+    {
+      value = info->libraryDescription;
+      value_length = sizeof (info->libraryDescription);
+    }
+  else if (g_str_equal (name, "library-manufacturer"))
+    {
+      value = info->manufacturerID;
+      value_length = sizeof (info->manufacturerID);
+    }
+  else
+    {
+      return NO_MATCH;
+    }
+
+  string = g_uri_unescape_segment (start, end, "");
+  if (string == NULL)
+    {
+      g_set_error (error, G_PKCS11_ERROR, G_PKCS11_ERROR_BAD_URI,
+                   _("The URI has invalid syntax. The '%s' field encoding is invalid."), name);
+      return FAILED;
+    }
+
+  string_length = strlen (string);
+  if (string_length > value_length)
+    {
+      g_set_error (error, G_PKCS11_ERROR, G_PKCS11_ERROR_BAD_URI,
+                   _("The URI has invalid syntax. The '%s' field is too long."), name);
+      g_free (string);
+      return FAILED;
+    }
+
+  /* All the fields are space (!) padded */
+  memset (value, ' ', value_length);
+  memcpy (value, string, string_length);
+  g_free (string);
+  return SUCCESS;
+}
+
+gboolean
+g_pkcs11_uri_parse (const gchar    *uri,
+                    CK_INFO        *library,
+                    CK_TOKEN_INFO  *token,
+                    GError        **error)
+{
+  const gchar *spos, *epos;
+  gchar *key = NULL;
+  gboolean ret;
+  gint res;
+
+  g_return_val_if_fail (uri, FALSE);
+  g_return_val_if_fail (library, FALSE);
+  g_return_val_if_fail (token, FALSE);
+  g_return_val_if_fail (!error || !*error, FALSE);
+
+  if (!g_str_has_prefix (uri, URI_PREFIX))
+    {
+      g_set_error_literal (error, G_PKCS11_ERROR, G_PKCS11_ERROR_BAD_URI,
+                           _("The URI has does not have the 'pkcs11' scheme."));
+      return FALSE;
+    }
+
+  /* All fields set to zero, including string fields */
+  memset (token, 0, sizeof (CK_TOKEN_INFO));
+  memset (library, 0, sizeof (CK_INFO));
+
+  ret = TRUE;
+  for (;;)
+    {
+      spos = strchr (uri, ';');
+      if (spos == NULL)
+        {
+          spos = uri + strlen (uri);
+          g_assert (*spos == '\0');
+          if (spos == uri)
+            break;
+        }
+
+      epos = strchr (uri, '=');
+      if (epos == NULL || spos == uri || epos == uri || epos >= spos)
+        {
+          g_set_error_literal (error, G_PKCS11_ERROR, G_PKCS11_ERROR_BAD_URI,
+                               _("The URI has invalid syntax. It must consist of key=value pairs."));
+          ret = FALSE;
+          break;
+        }
+
+      g_free (key);
+      key = g_strndup (uri, epos - uri);
+      epos++;
+
+      res = parse_string_field (key, epos, spos, library, token, error);
+      if (res == NO_MATCH)
+        {
+          g_message ("Ignoring unsupported field '%s'", key);
+        }
+      else if (res != SUCCESS)
+        {
+          ret = FALSE;
+          break;
+        }
+
+      if (*spos == '\0')
+        break;
+      uri = spos + 1;
+    }
+
+  g_free (key);
+  return ret;
+}
diff --git a/tls/pkcs11/gpkcs11uri.h b/tls/pkcs11/gpkcs11uri.h
new file mode 100644
index 0000000..95f96d0
--- /dev/null
+++ b/tls/pkcs11/gpkcs11uri.h
@@ -0,0 +1,36 @@
+/* GIO - Small GLib wrapper of PKCS#11 for use in GTls
+ *
+ * Copyright © 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#ifndef __G_PKCS11_URI_H__
+#define __G_PKCS11_URI_H__
+
+#include <glib.h>
+
+#include "pkcs11.h"
+
+G_BEGIN_DECLS
+
+gboolean               g_pkcs11_uri_parse                 (const gchar      *uri,
+                                                           CK_INFO          *library,
+                                                           CK_TOKEN_INFO    *token,
+                                                           GError **error);
+
+gboolean               g_pkcs11_uri_info_match            (CK_INFO          *match_library,
+                                                           CK_INFO          *library,
+                                                           CK_TOKEN_INFO    *match_token,
+                                                           CK_TOKEN_INFO    *token);
+
+G_END_DECLS
+
+#endif /* __G_PKCS11_URI_H___ */
diff --git a/tls/pkcs11/gpkcs11util.h b/tls/pkcs11/gpkcs11util.h
new file mode 100644
index 0000000..a7af5f7
--- /dev/null
+++ b/tls/pkcs11/gpkcs11util.h
@@ -0,0 +1,41 @@
+/* GIO - Small GLib wrapper of PKCS#11 for use in GTls
+ *
+ * Copyright © 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#ifndef __G_PKCS11_UTIL_H__
+#define __G_PKCS11_UTIL_H__
+
+#include <glib.h>
+
+#include "pkcs11.h"
+
+G_BEGIN_DECLS
+
+#define                G_PKCS11_VENDOR_CODE               0x47000000 /* G000 */
+
+enum {
+  G_PKCS11_ERROR_BAD_URI = (CKR_VENDOR_DEFINED | (G_PKCS11_VENDOR_CODE + 1)),
+};
+
+#define                G_PKCS11_ERROR                     (g_pkcs11_get_error_domain ())
+
+GQuark                 g_pkcs11_get_error_domain          (void) G_GNUC_CONST;
+
+const gchar*           g_pkcs11_rv_to_message             (CK_RV rv);
+
+void                   g_pkcs11_propagate_error           (GError **error,
+                                                           CK_RV rv);
+
+G_END_DECLS
+
+#endif /* __G_PKCS11_UTIL_H___ */
diff --git a/tls/pkcs11/pkcs11-trust-assertions.h b/tls/pkcs11/pkcs11-trust-assertions.h
new file mode 100644
index 0000000..decfd32
--- /dev/null
+++ b/tls/pkcs11/pkcs11-trust-assertions.h
@@ -0,0 +1,56 @@
+/*
+ * pkcs11x.h
+ *  Copyright 2010 Collabora, Ltd
+ *
+ * This file is free software; as a special exception the author gives
+ * unlimited permission to copy and/or distribute it, with or without
+ * modifications, as long as this notice is preserved.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * The latest version of this file is at:
+ *
+ * git://thewalter.net/git/pkcs11-trust-assertions
+ *
+ * or viewable on the web at:
+ *
+ * http://thewalter.net/git/cgit.cgi/pkcs11-trust-assertions/tree/pkcs11-trust-assertions.h
+ *
+ */
+
+#ifndef PKCS11_TRUST_ASSERTIONS_H
+#define PKCS11_TRUST_ASSERTIONS_H
+
+#include "pkcs11.h"
+
+#define CKA_XDG   (CKA_VENDOR_DEFINED | 0x58444700UL /* XDG0 */ )
+#define CKO_XDG   (CKA_VENDOR_DEFINED | 0x58444700UL /* XDG0 */ )
+
+/* -------------------------------------------------------------------
+ * TRUST ASSERTIONS
+ */
+
+#define CKO_X_TRUST_ASSERTION                    (CKO_XDG + 100)
+
+#define CKA_X_ASSERTION_TYPE                     (CKA_XDG + 1)
+
+#define CKA_X_CERTIFICATE_VALUE                  (CKA_XDG + 2)
+
+#define CKA_X_PURPOSE                            (CKA_XDG + 3)
+
+#define CKA_X_PEER                               (CKA_XDG + 4)
+
+typedef CK_ULONG CK_X_ASSERTION_TYPE;
+
+#define CKT_X_UNTRUSTED_CERTIFICATE              1UL
+
+#define CKT_X_PINNED_CERTIFICATE                 2UL
+
+#define CKT_X_ANCHORED_CERTIFICATE               3UL
+
+#endif /* PKCS11_TRUST_ASSERTIONS_H */



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