[glib-networking/tls-database] pkcs11: Load PKCS#11 trust lookup options from config



commit a0281f4c78c899b5067d8229dc9c3bcbdd9d1f05
Author: Stef Walter <stefw collabora co uk>
Date:   Thu Jan 6 17:31:27 2011 -0800

    pkcs11: Load PKCS#11 trust lookup options from config
    
    Use the /etc/pkcs11/pkcs11-options.conf and /etc/pkcs11-options.defaults
    files to enumerate the slots that we should use for lookup of trust
    assertions.

 tls/gnutls/gtlspkcs11database-gnutls.c |  196 +++++++++++++++++++++++++-------
 tls/pkcs11/gpkcs11slot.c               |   35 ++++++
 tls/pkcs11/gpkcs11slot.h               |    6 +-
 tls/pkcs11/gpkcs11uri.c                |  110 +++++++++++++-----
 tls/pkcs11/gpkcs11uri.h                |   15 ++-
 5 files changed, 286 insertions(+), 76 deletions(-)
---
diff --git a/tls/gnutls/gtlspkcs11database-gnutls.c b/tls/gnutls/gtlspkcs11database-gnutls.c
index 3c8061b..9181a02 100644
--- a/tls/gnutls/gtlspkcs11database-gnutls.c
+++ b/tls/gnutls/gtlspkcs11database-gnutls.c
@@ -46,6 +46,7 @@ struct _GTlsPkcs11DatabaseGnutlsPrivate
   GList *pkcs11_slots;
   GList *modules;
   GList *initialized;
+  GList *trust_lookups;
 };
 
 static CK_RV
@@ -157,7 +158,8 @@ load_and_initialize_module (GTlsPkcs11DatabaseGnutls   *self,
   if (!module)
     {
       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   "Error loading PKCS#11 module: %s", g_module_error ());
+                   _("Couldn't load PKCS#11 module: %s: %s"),
+                   path, g_module_error ());
       return NULL;
     }
 
@@ -165,7 +167,8 @@ load_and_initialize_module (GTlsPkcs11DatabaseGnutls   *self,
   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 ());
+                   _("Couldn't load PKCS#11 module: %s: %s"),
+                   path, g_module_error ());
       g_module_close (module);
       return NULL;
     }
@@ -175,8 +178,8 @@ load_and_initialize_module (GTlsPkcs11DatabaseGnutls   *self,
   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));
+                   _("Couldn't load PKCS#11 module: %s: %s"),
+                   path, _("No function list"));
       g_module_close (module);
       return NULL;
     }
@@ -204,8 +207,8 @@ load_and_initialize_module (GTlsPkcs11DatabaseGnutls   *self,
   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));
+                   _("Couldn't initialize PKCS#11 module: %s, %s"),
+                   path, g_pkcs11_rv_to_message (rv));
       g_module_close (module);
       return NULL;
     }
@@ -257,6 +260,117 @@ enumerate_and_setup_slots (GTlsPkcs11DatabaseGnutls   *self,
 }
 
 static gboolean
+load_and_setup_all_modules (GTlsPkcs11DatabaseGnutls *self,
+                            GCancellable             *cancellable,
+                            GError                  **error)
+{
+  CK_FUNCTION_LIST_PTR funcs;
+  gchar **paths, **path;
+  GError *err = NULL;
+  gboolean any_success = FALSE;
+  gboolean any_failure = FALSE;
+
+  paths = list_registered_pkcs11_module_paths (PKCS11_REGISTRY_DIR, &err);
+  if (!paths)
+    {
+      if (err)
+        {
+          g_propagate_error (error, err);
+          return FALSE;
+        }
+      return TRUE;
+    }
+
+  for (path = paths; *path; ++path)
+    {
+      funcs = load_and_initialize_module (self, *path, &err);
+      if (funcs && enumerate_and_setup_slots (self, funcs, &err))
+        {
+          /* Any module initialized */
+          any_success = TRUE;
+          g_clear_error (error);
+          continue;
+        }
+
+      /* All modules have failed */
+      if (!any_success && !any_failure)
+        g_propagate_error (error, err);
+      any_failure = TRUE;
+    }
+
+  g_strfreev (paths);
+  return any_failure && !any_success;
+}
+
+static void
+load_pkcs11_options (GTlsPkcs11DatabaseGnutls *self)
+{
+  GKeyFile *key_file;
+  GError *error = NULL;
+  const gchar *path;
+  gchar *value;
+  gchar **uris, **u;
+  GPkcs11UriInfo *uri_info;
+
+  key_file = g_key_file_new ();
+
+  /* Load the defaults */
+  path = "/etc/pkcs11/pkcs11-options.defaults";
+  if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error))
+    {
+      g_warning ("couldn't parse %s file: %s", path, error->message);
+      g_clear_error (&error);
+    }
+
+  /* Load any overrides */
+  path = "/etc/pkcs11/pkcs11-options.conf";
+  if (g_file_test (path, G_FILE_TEST_EXISTS) &&
+      !g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error))
+    {
+      g_warning ("couldn't parse %s file: %s", path, error->message);
+      g_clear_error (&error);
+    }
+
+  value = g_key_file_get_string (key_file, "trust-assertions", "lookups", NULL);
+  uris = g_strsplit_set (value ? value : "", " \t", -1);
+  g_free (value);
+
+  g_key_file_free (key_file);
+
+  for (u = uris; u && *u; ++u)
+    {
+      uri_info = g_pkcs11_uri_parse (*u, &error);
+      if (error)
+        {
+          g_warning ("invalid PKCS#11 URI in options: %s: %s",
+                     *u, error->message);
+          g_clear_error (&error);
+        }
+      else
+        {
+          self->priv->trust_lookups = g_list_prepend (self->priv->trust_lookups, uri_info);
+        }
+    }
+
+  g_strfreev (uris);
+}
+
+static gboolean
+slot_is_for_trust_lookup (GTlsPkcs11DatabaseGnutls  *self,
+                          GPkcs11Slot               *slot)
+{
+  GList *l;
+
+  for (l = self->priv->trust_lookups; l; l = g_list_next (l))
+    {
+      if (g_pkcs11_slot_matches_uri (slot, l->data))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
 find_objects_on_all_slots (GTlsPkcs11DatabaseGnutls *self,
                            GPkcs11Array            *match,
                            CK_ATTRIBUTE_TYPE       *attr_types,
@@ -265,8 +379,8 @@ find_objects_on_all_slots (GTlsPkcs11DatabaseGnutls *self,
                            gpointer                 user_data,
                            GError                 **error)
 {
+  GPkcs11SlotFindStatus status = G_PKCS11_SLOT_FIND_COMPLETED;
   GList *l;
-  GPkcs11SlotFindStatus status;
 
   for (l = self->priv->pkcs11_slots; l; l = g_list_next (l))
     {
@@ -281,6 +395,31 @@ find_objects_on_all_slots (GTlsPkcs11DatabaseGnutls *self,
 }
 
 static gboolean
+find_objects_on_trust_slots (GTlsPkcs11DatabaseGnutls *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;
+  GList *l;
+
+  for (l = self->priv->pkcs11_slots; l; l = g_list_next (l))
+    {
+      if (slot_is_for_trust_lookup (self, l->data))
+        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,
@@ -338,6 +477,11 @@ g_tls_pkcs11_database_gnutls_finalize (GObject *object)
   g_list_free (self->priv->pkcs11_slots);
   self->priv->pkcs11_slots = NULL;
 
+  for (l = self->priv->trust_lookups; l; l = g_list_next (l))
+    g_pkcs11_uri_info_free (l->data);
+  g_list_free (self->priv->trust_lookups);
+  self->priv->trust_lookups = NULL;
+
   G_OBJECT_CLASS (g_tls_pkcs11_database_gnutls_parent_class)->finalize (object);
 }
 
@@ -396,8 +540,8 @@ g_tls_pkcs11_database_gnutls_lookup_assertion (GTlsDatabaseGnutls          *data
     }
 
   if (ready)
-    find_objects_on_all_slots (self, match, NULL, 0, find_if_any_exist,
-                               &found, error);
+    find_objects_on_trust_slots (self, match, NULL, 0, find_if_any_exist,
+                                 &found, error);
 
   g_pkcs11_array_unref (match);
   return found;
@@ -460,38 +604,12 @@ g_tls_pkcs11_database_gnutls_initable_init (GInitable     *initable,
                                             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);
+  if (!load_and_setup_all_modules (self, cancellable, error))
+    return 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;
+  load_pkcs11_options (self);
+  return TRUE;
 }
 
 static void
diff --git a/tls/pkcs11/gpkcs11slot.c b/tls/pkcs11/gpkcs11slot.c
index 02bf344..bd6cf69 100644
--- a/tls/pkcs11/gpkcs11slot.c
+++ b/tls/pkcs11/gpkcs11slot.c
@@ -400,3 +400,38 @@ g_pkcs11_slot_find_objects (GPkcs11Slot           *self,
 
   return status;
 }
+
+gboolean
+g_pkcs11_slot_matches_uri (GPkcs11Slot            *self,
+                           GPkcs11UriInfo         *uri_info)
+{
+  CK_INFO library;
+  CK_TOKEN_INFO token;
+  CK_RV rv;
+
+  g_return_val_if_fail (G_IS_PKCS11_SLOT (self), FALSE);
+  g_return_val_if_fail (uri_info, FALSE);
+
+  memset (&library, 0, sizeof (library));
+  rv = (self->priv->module->C_GetInfo) (&library);
+  if (rv != CKR_OK)
+    {
+      g_warning ("call to C_GetInfo on PKCS#11 module failed: %s",
+                 g_pkcs11_rv_to_message (rv));
+      return FALSE;
+    }
+
+  memset (&token, 0, sizeof (token));
+  rv = (self->priv->module->C_GetTokenInfo) (self->priv->slot_id, &token);
+  if (rv == CKR_TOKEN_NOT_PRESENT)
+    return FALSE;
+
+  if (rv != CKR_OK)
+    {
+      g_warning ("call to C_GetTokenInfo on PKCS#11 module failed: %s",
+                 g_pkcs11_rv_to_message (rv));
+      return FALSE;
+    }
+
+  return g_pkcs11_uri_info_match (uri_info, &library, &token);
+}
diff --git a/tls/pkcs11/gpkcs11slot.h b/tls/pkcs11/gpkcs11slot.h
index fcc017b..3aee754 100644
--- a/tls/pkcs11/gpkcs11slot.h
+++ b/tls/pkcs11/gpkcs11slot.h
@@ -18,6 +18,7 @@
 #include <gio/gio.h>
 
 #include "gpkcs11array.h"
+#include "gpkcs11uri.h"
 
 #include "pkcs11.h"
 
@@ -71,6 +72,9 @@ GPkcs11SlotFindStatus       g_pkcs11_slot_find_objects        (GPkcs11Slot
                                                                gpointer                user_data,
                                                                GError                **error);
 
+gboolean                    g_pkcs11_slot_matches_uri         (GPkcs11Slot            *self,
+                                                               GPkcs11UriInfo         *uri_info);
+
 G_END_DECLS
 
-#endif /* __G_TLS_CERTIFICATE_GNUTLS_H___ */
+#endif /* __G_PKCS11_SLOT_H___ */
diff --git a/tls/pkcs11/gpkcs11uri.c b/tls/pkcs11/gpkcs11uri.c
index 2ad8ff5..2d159c5 100644
--- a/tls/pkcs11/gpkcs11uri.c
+++ b/tls/pkcs11/gpkcs11uri.c
@@ -42,8 +42,7 @@ static gint
 parse_string_field (const gchar    *name,
                     const gchar    *start,
                     const gchar    *end,
-                    CK_INFO        *info,
-                    CK_TOKEN_INFO  *token,
+                    GPkcs11UriInfo *info,
                     GError        **error)
 {
   unsigned char *value;
@@ -54,38 +53,37 @@ parse_string_field (const gchar    *name,
   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);
+      value = info->token.model;
+      value_length = sizeof (info->token.model);
     }
   else if (g_str_equal (name, "manufacturer"))
     {
-      value = token->manufacturerID;
-      value_length = sizeof (token->manufacturerID);
+      value = info->token.manufacturerID;
+      value_length = sizeof (info->token.manufacturerID);
     }
   else if (g_str_equal (name, "serial"))
     {
-      value = token->serialNumber;
-      value_length = sizeof (token->serialNumber);
+      value = info->token.serialNumber;
+      value_length = sizeof (info->token.serialNumber);
     }
   else if (g_str_equal (name, "token"))
     {
-      value = token->label;
-      value_length = sizeof (token->label);
+      value = info->token.label;
+      value_length = sizeof (info->token.label);
     }
   else if (g_str_equal (name, "library-description"))
     {
-      value = info->libraryDescription;
-      value_length = sizeof (info->libraryDescription);
+      value = info->library.libraryDescription;
+      value_length = sizeof (info->library.libraryDescription);
     }
   else if (g_str_equal (name, "library-manufacturer"))
     {
-      value = info->manufacturerID;
-      value_length = sizeof (info->manufacturerID);
+      value = info->library.manufacturerID;
+      value_length = sizeof (info->library.manufacturerID);
     }
   else
     {
@@ -116,34 +114,28 @@ parse_string_field (const gchar    *name,
   return SUCCESS;
 }
 
-gboolean
+GPkcs11UriInfo*
 g_pkcs11_uri_parse (const gchar    *uri,
-                    CK_INFO        *library,
-                    CK_TOKEN_INFO  *token,
                     GError        **error)
 {
   const gchar *spos, *epos;
+  GPkcs11UriInfo *result;
   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);
+  g_return_val_if_fail (uri, NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
 
   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;
+      return NULL;
     }
 
   /* All fields set to zero, including string fields */
-  memset (token, 0, sizeof (CK_TOKEN_INFO));
-  memset (library, 0, sizeof (CK_INFO));
+  result = g_slice_new0 (GPkcs11UriInfo);
 
-  ret = TRUE;
   for (;;)
     {
       spos = strchr (uri, ';');
@@ -160,7 +152,8 @@ g_pkcs11_uri_parse (const gchar    *uri,
         {
           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;
+          g_pkcs11_uri_info_free (result);
+          result = NULL;
           break;
         }
 
@@ -168,14 +161,15 @@ g_pkcs11_uri_parse (const gchar    *uri,
       key = g_strndup (uri, epos - uri);
       epos++;
 
-      res = parse_string_field (key, epos, spos, library, token, error);
+      res = parse_string_field (key, epos, spos, result, error);
       if (res == NO_MATCH)
         {
           g_message ("Ignoring unsupported field '%s'", key);
         }
       else if (res != SUCCESS)
         {
-          ret = FALSE;
+          g_pkcs11_uri_info_free (result);
+          result = NULL;
           break;
         }
 
@@ -185,5 +179,59 @@ g_pkcs11_uri_parse (const gchar    *uri,
     }
 
   g_free (key);
-  return ret;
+  return result;
+}
+
+#define match_member(x, y, m) \
+  ((x) && (y) && memcmp (&x->m, &y->m, sizeof (&x->m)) == 0)
+
+gboolean
+g_pkcs11_uri_info_match (GPkcs11UriInfo    *match,
+                         CK_INFO           *library,
+                         CK_TOKEN_INFO     *token)
+{
+  CK_INFO *match_library;
+  CK_TOKEN_INFO *match_token;
+
+  g_return_val_if_fail (match, FALSE);
+
+  match_library = &match->library;
+  match_token = &match->token;
+
+  if (match_library->libraryVersion.major || match_library->libraryVersion.minor)
+    if (!match_member (match_library, library, cryptokiVersion))
+        return FALSE;
+
+  if (match->library.libraryDescription[0])
+    if (!match_member (match_library, library, libraryDescription))
+      return FALSE;
+
+  if (match->library.manufacturerID[0])
+    if (!match_member (match_library, library, manufacturerID))
+      return FALSE;
+
+  if (match->token.model[0])
+    if (!match_member (match_token, token, model))
+      return FALSE;
+
+  if (match->token.manufacturerID[0])
+    if (!match_member (match_token, token, manufacturerID))
+      return FALSE;
+
+  if (match->token.serialNumber[0])
+    if (!match_member (match_token, token, serialNumber))
+      return FALSE;
+
+  if (match->token.label[0])
+    if (!match_member (match_token, token, label))
+      return FALSE;
+
+  return TRUE;
+}
+
+void
+g_pkcs11_uri_info_free (GPkcs11UriInfo    *info)
+{
+  if (info)
+    g_slice_free (GPkcs11UriInfo, info);
 }
diff --git a/tls/pkcs11/gpkcs11uri.h b/tls/pkcs11/gpkcs11uri.h
index 95f96d0..313dd9c 100644
--- a/tls/pkcs11/gpkcs11uri.h
+++ b/tls/pkcs11/gpkcs11uri.h
@@ -21,16 +21,21 @@
 
 G_BEGIN_DECLS
 
-gboolean               g_pkcs11_uri_parse                 (const gchar      *uri,
-                                                           CK_INFO          *library,
-                                                           CK_TOKEN_INFO    *token,
+typedef struct _GPkcs11UriInfo
+{
+  CK_INFO library;
+  CK_TOKEN_INFO token;
+} GPkcs11UriInfo;
+
+GPkcs11UriInfo *       g_pkcs11_uri_parse                 (const gchar      *uri,
                                                            GError **error);
 
-gboolean               g_pkcs11_uri_info_match            (CK_INFO          *match_library,
+gboolean               g_pkcs11_uri_info_match            (GPkcs11UriInfo    *match,
                                                            CK_INFO          *library,
-                                                           CK_TOKEN_INFO    *match_token,
                                                            CK_TOKEN_INFO    *token);
 
+void                   g_pkcs11_uri_info_free             (GPkcs11UriInfo    *info);
+
 G_END_DECLS
 
 #endif /* __G_PKCS11_URI_H___ */



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