[seahorse] pkcs11: Support for PKCS#11 key generation



commit 6df2460eb5cef806c1df147b93a7beb3700f4459
Author: Stef Walter <stefw collabora co uk>
Date:   Mon Nov 14 07:13:02 2011 +0100

    pkcs11: Support for PKCS#11 key generation
    
     * Used to generate keys on smart cards and the like
     * Also code for detecting which mechanisms a slot supports.

 libseahorse/seahorse-key-manager-store.c |    1 +
 pkcs11/Makefile.am                       |    4 +-
 pkcs11/seahorse-pkcs11-backend.c         |   51 +++-
 pkcs11/seahorse-pkcs11-backend.h         |    3 +
 pkcs11/seahorse-pkcs11-generate.c        |  517 ++++++++++++++++++++++++++++++
 pkcs11/seahorse-pkcs11-generate.h        |   35 ++
 pkcs11/seahorse-pkcs11-generate.xml      |  246 ++++++++++++++
 pkcs11/seahorse-token.c                  |   42 +++-
 pkcs11/seahorse-token.h                  |    5 +
 9 files changed, 897 insertions(+), 7 deletions(-)
---
diff --git a/libseahorse/seahorse-key-manager-store.c b/libseahorse/seahorse-key-manager-store.c
index 2765978..1e7ccf2 100644
--- a/libseahorse/seahorse-key-manager-store.c
+++ b/libseahorse/seahorse-key-manager-store.c
@@ -646,6 +646,7 @@ seahorse_key_manager_store_new (GcrCollection *collection,
 	self = g_object_new (SEAHORSE_TYPE_KEY_MANAGER_STORE,
 	                     "collection", filtered,
 	                     "settings", settings,
+	                     "mode", GCR_COLLECTION_MODEL_LIST,
 	                     NULL);
 	pred->custom_target = self;
 	g_object_unref (filtered);
diff --git a/pkcs11/Makefile.am b/pkcs11/Makefile.am
index 118a340..75da6a2 100644
--- a/pkcs11/Makefile.am
+++ b/pkcs11/Makefile.am
@@ -20,6 +20,7 @@ libseahorse_pkcs11_la_SOURCES = \
 	seahorse-pkcs11-actions.c seahorse-pkcs11-actions.h \
 	seahorse-pkcs11-backend.c seahorse-pkcs11-backend.h \
 	seahorse-pkcs11-helpers.c seahorse-pkcs11-helpers.h \
+	seahorse-pkcs11-generate.c seahorse-pkcs11-generate.h \
 	seahorse-pkcs11-operations.c seahorse-pkcs11-operations.h \
 	seahorse-pkcs11-properties.c seahorse-pkcs11-properties.h \
 	seahorse-pkcs11.c seahorse-pkcs11.h \
@@ -30,7 +31,8 @@ libseahorse_pkcs11_la_LIBADD = \
 	$(top_builddir)/libseahorse/libseahorse.la \
 	$(GCR_LIBS)
 
-ui_DATA =
+ui_DATA = \
+	seahorse-pkcs11-generate.xml
 
 EXTRA_DIST = \
 	$(ui_DATA)
diff --git a/pkcs11/seahorse-pkcs11-backend.c b/pkcs11/seahorse-pkcs11-backend.c
index 273de7f..65c32d7 100644
--- a/pkcs11/seahorse-pkcs11-backend.c
+++ b/pkcs11/seahorse-pkcs11-backend.c
@@ -22,6 +22,7 @@
 #include "config.h"
 
 #include "seahorse-pkcs11-backend.h"
+#include "seahorse-pkcs11-generate.h"
 #include "seahorse-token.h"
 
 #include "seahorse-backend.h"
@@ -29,6 +30,8 @@
 #include "seahorse-registry.h"
 #include "seahorse-util.h"
 
+#include <gcr/gcr-base.h>
+
 #include <gck/gck.h>
 
 #include <glib/gi18n.h>
@@ -86,6 +89,8 @@ seahorse_pkcs11_backend_init (SeahorsePkcs11Backend *self)
 		}
 		self->blacklist = g_list_prepend (self->blacklist, uri);
 	}
+
+	seahorse_pkcs11_generate_register ();
 }
 
 static gboolean
@@ -95,10 +100,6 @@ is_token_usable (SeahorsePkcs11Backend *self,
 {
 	GList *l;
 
-	if (token->flags & CKF_WRITE_PROTECTED) {
-		/* _gcr_debug ("token is not importable: %s: write protected", token->label); */
-		return FALSE;
-	}
 	if (!(token->flags & CKF_TOKEN_INITIALIZED)) {
 		/* _gcr_debug ("token is not importable: %s: not initialized", token->label); */
 		return FALSE;
@@ -117,7 +118,6 @@ is_token_usable (SeahorsePkcs11Backend *self,
 	return TRUE;
 }
 
-
 static void
 on_initialized_registered (GObject *unused,
                            GAsyncResult *result,
@@ -291,3 +291,44 @@ seahorse_pkcs11_backend_get (void)
 	g_return_val_if_fail (pkcs11_backend, NULL);
 	return pkcs11_backend;
 }
+
+static gboolean
+on_filter_writable (GObject *object,
+                    gpointer user_data)
+{
+	SeahorseToken *token = SEAHORSE_TOKEN (object);
+	guint mechanism = GPOINTER_TO_UINT (user_data);
+	GckTokenInfo *info;
+
+	info = seahorse_token_get_info (token);
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	if (info->flags & CKF_WRITE_PROTECTED)
+		return FALSE;
+
+	if (mechanism != G_MAXUINT) {
+		if (!seahorse_token_has_mechanism (token, (gulong)mechanism))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+GcrCollection *
+seahorse_pkcs11_backend_get_writable_tokens (SeahorsePkcs11Backend *self,
+                                             gulong with_mechanism)
+{
+	gpointer mechanism;
+
+	self = self ? self : seahorse_pkcs11_backend_get ();
+	g_return_val_if_fail (SEAHORSE_IS_PKCS11_BACKEND (self), NULL);
+
+	if (with_mechanism == GCK_INVALID)
+		mechanism = GUINT_TO_POINTER (G_MAXUINT);
+	else
+		mechanism = GUINT_TO_POINTER (with_mechanism);
+
+	return gcr_filter_collection_new_with_callback (GCR_COLLECTION (self),
+	                                                on_filter_writable,
+	                                                mechanism, NULL);
+}
diff --git a/pkcs11/seahorse-pkcs11-backend.h b/pkcs11/seahorse-pkcs11-backend.h
index b4b040e..e367be1 100644
--- a/pkcs11/seahorse-pkcs11-backend.h
+++ b/pkcs11/seahorse-pkcs11-backend.h
@@ -43,4 +43,7 @@ GType                    seahorse_pkcs11_backend_get_type      (void) G_GNUC_CON
 
 SeahorsePkcs11Backend *  seahorse_pkcs11_backend_get           (void);
 
+GcrCollection *          seahorse_pkcs11_backend_get_writable_tokens (SeahorsePkcs11Backend *self,
+                                                                      gulong with_mechanism);
+
 #endif /* SEAHORSE_PKCS11_BACKEND_H_ */
diff --git a/pkcs11/seahorse-pkcs11-generate.c b/pkcs11/seahorse-pkcs11-generate.c
new file mode 100644
index 0000000..f78abea
--- /dev/null
+++ b/pkcs11/seahorse-pkcs11-generate.c
@@ -0,0 +1,517 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "seahorse-pkcs11-backend.h"
+#include "seahorse-pkcs11-generate.h"
+#include "seahorse-token.h"
+
+#include "seahorse-action.h"
+#include "seahorse-progress.h"
+#include "seahorse-interaction.h"
+#include "seahorse-registry.h"
+#include "seahorse-util.h"
+
+#include <glib/gi18n.h>
+
+#include <gcr/gcr.h>
+
+#include <gck/gck.h>
+#include <gck/pkcs11.h>
+
+#define SEAHORSE_PKCS11_GENERATE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PKCS11_GENERATE, SeahorsePkcs11Generate))
+#define SEAHORSE_IS_PKCS11_GENERATE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_PKCS11_GENERATE))
+#define SEAHORSE_PKCS11_GENERATE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_PKCS11_GENERATE, SeahorsePkcs11GenerateClass))
+#define SEAHORSE_IS_PKCS11_GENERATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_PKCS11_GENERATE))
+#define SEAHORSE_PKCS11_GENERATE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_PKCS11_GENERATE, SeahorsePkcs11GenerateClass))
+
+typedef struct _SeahorsePkcs11Generate SeahorsePkcs11Generate;
+typedef struct _SeahorsePkcs11GenerateClass SeahorsePkcs11GenerateClass;
+
+struct _SeahorsePkcs11Generate {
+	GtkDialog dialog;
+
+	GtkEntry *label_entry;
+
+	SeahorseToken *token;
+	GtkComboBox *token_box;
+	GcrCollectionModel *token_model;
+
+	GckMechanism *mechanism;
+	GtkListStore *mechanism_store;
+	GtkComboBox *mechanism_box;
+
+	GtkSpinButton *bits_entry;
+
+	GCancellable *cancellable;
+	GckAttributes *pub_attrs;
+	GckAttributes *prv_attrs;
+};
+
+struct _SeahorsePkcs11GenerateClass {
+	GtkDialogClass dialog_class;
+};
+
+G_DEFINE_TYPE (SeahorsePkcs11Generate, seahorse_pkcs11_generate, GTK_TYPE_DIALOG);
+
+enum {
+	MECHANISM_LABEL,
+	MECHANISM_TYPE,
+	MECHANISM_N_COLS
+};
+
+static GType MECHANISM_TYPES[] = {
+	G_TYPE_STRING,
+	G_TYPE_ULONG
+};
+
+struct {
+	gulong mechanism_type;
+	const gchar *label;
+} AVAILABLE_MECHANISMS[] = {
+	{ CKM_RSA_PKCS_KEY_PAIR_GEN, N_("RSA") },
+};
+
+static void
+seahorse_pkcs11_generate_init (SeahorsePkcs11Generate *self)
+{
+
+}
+
+static void
+update_response (SeahorsePkcs11Generate *self)
+{
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK,
+	                                   self->token != NULL && self->mechanism != NULL);
+}
+
+static void
+complete_generate (SeahorsePkcs11Generate *self,
+                   GError **error)
+{
+	g_assert (self->cancellable != NULL);
+	g_assert (error != NULL);
+
+	if (*error != NULL)
+		seahorse_util_handle_error (error, NULL, _("Couldn't generate private key"));
+	else
+		seahorse_token_refresh_async (self->token, self->cancellable, NULL, NULL);
+
+	g_clear_object (&self->cancellable);
+	gck_attributes_unref (self->pub_attrs);
+	gck_attributes_unref (self->prv_attrs);
+	self->pub_attrs = self->prv_attrs = NULL;
+}
+
+static void
+prepare_generate (SeahorsePkcs11Generate *self)
+{
+	CK_BYTE rsa_public_exponent[] = { 0x01, 0x00, 0x01 }; /* 65537 in bytes */
+	const gchar *label;
+
+	g_assert (self->cancellable == NULL);
+	g_assert (self->mechanism);
+
+	self->cancellable = g_cancellable_new ();
+
+	self->pub_attrs = gck_attributes_new ();
+	self->prv_attrs = gck_attributes_new ();
+
+	gck_attributes_add_ulong (self->pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+	gck_attributes_add_ulong (self->prv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
+
+	gck_attributes_add_boolean (self->pub_attrs, CKA_TOKEN, TRUE);
+	gck_attributes_add_boolean (self->prv_attrs, CKA_TOKEN, TRUE);
+
+	gck_attributes_add_boolean (self->prv_attrs, CKA_PRIVATE, TRUE);
+	gck_attributes_add_boolean (self->prv_attrs, CKA_SENSITIVE, TRUE);
+
+	label = gtk_entry_get_text (self->label_entry);
+	gck_attributes_add_string (self->pub_attrs, CKA_LABEL, label);
+	gck_attributes_add_string (self->prv_attrs, CKA_LABEL, label);
+
+	if (self->mechanism->type == CKM_RSA_PKCS_KEY_PAIR_GEN) {
+		gck_attributes_add_boolean (self->pub_attrs, CKA_ENCRYPT, TRUE);
+		gck_attributes_add_boolean (self->pub_attrs, CKA_VERIFY, TRUE);
+		gck_attributes_add_boolean (self->pub_attrs, CKA_WRAP, TRUE);
+
+		gck_attributes_add_boolean (self->prv_attrs, CKA_DECRYPT, TRUE);
+		gck_attributes_add_boolean (self->prv_attrs, CKA_SIGN, TRUE);
+		gck_attributes_add_boolean (self->prv_attrs, CKA_UNWRAP, TRUE);
+
+		gck_attributes_add_data (self->pub_attrs, CKA_PUBLIC_EXPONENT,
+		                         rsa_public_exponent, sizeof (rsa_public_exponent));
+		gck_attributes_add_ulong (self->pub_attrs, CKA_MODULUS_BITS,
+		                          gtk_spin_button_get_value_as_int (self->bits_entry));
+
+	} else {
+		g_warning ("currently no support for this mechanism");
+	}
+}
+
+static void
+on_generate_complete (GObject *object,
+                      GAsyncResult *result,
+                      gpointer user_data)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (user_data);
+	GError *error = NULL;
+
+	gck_session_generate_key_pair_finish (GCK_SESSION (object), result, NULL, NULL, &error);
+	complete_generate (self, &error);
+
+	g_object_unref (self);
+}
+
+static void
+on_generate_open_session (GObject *object,
+                          GAsyncResult *result,
+                          gpointer user_data)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (user_data);
+	GError *error = NULL;
+	GckSession *session;
+
+	session = gck_session_open_finish (result, &error);
+	if (session) {
+		gck_session_generate_key_pair_async (session, self->mechanism,
+		                                     self->pub_attrs, self->prv_attrs,
+		                                     self->cancellable, on_generate_complete,
+		                                     g_object_ref (self));
+		g_object_unref (session);
+
+	} else {
+		complete_generate (self, &error);
+	}
+
+	g_object_unref (self);
+}
+
+static const gchar *
+get_available_mechanism_label (gulong type)
+{
+	guint i;
+
+	for (i = 0; i < G_N_ELEMENTS (AVAILABLE_MECHANISMS); i++) {
+		if (AVAILABLE_MECHANISMS[i].mechanism_type == type)
+			return AVAILABLE_MECHANISMS[i].label;
+	}
+
+	return NULL;
+}
+
+static void
+on_token_changed (GtkComboBox *combo_box,
+                  gpointer user_data)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (user_data);
+	GtkTreeIter iter;
+	GArray *mechanisms;
+	GObject *object;
+	gulong type, otype;
+	gboolean valid;
+	GtkTreeModel *model;
+	const gchar *label;
+	guint i;
+
+	g_clear_object (&self->token);
+
+	if (gtk_combo_box_get_active_iter (combo_box, &iter)) {
+		object = gcr_collection_model_object_for_iter (self->token_model, &iter);
+		self->token = g_object_ref (object);
+	}
+
+	model = GTK_TREE_MODEL (self->mechanism_store);
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+	if (self->token) {
+		mechanisms = seahorse_token_get_mechanisms (self->token);
+		for (i = 0; mechanisms && i < mechanisms->len; i++) {
+			type = g_array_index (mechanisms, gulong, i);
+			label = get_available_mechanism_label (type);
+			if (label == NULL)
+				continue;
+			while (valid) {
+				gtk_tree_model_get (model, &iter, MECHANISM_TYPE, &otype, -1);
+				if (otype == type)
+					break;
+				valid = gtk_list_store_remove (self->mechanism_store, &iter);
+			}
+			if (!valid)
+				gtk_list_store_append (self->mechanism_store, &iter);
+			gtk_list_store_set (self->mechanism_store, &iter,
+			                    MECHANISM_TYPE, type,
+			                    MECHANISM_LABEL, label,
+			                    -1);
+		}
+	}
+	while (valid)
+		valid = gtk_list_store_remove (self->mechanism_store, &iter);
+
+	/* Select first mechanism if none are selected */
+	if (!gtk_combo_box_get_active_iter (self->mechanism_box, &iter))
+		if (gtk_tree_model_get_iter_first (model, &iter))
+			gtk_combo_box_set_active_iter (self->mechanism_box, &iter);
+
+	update_response (self);
+}
+
+static void
+on_mechanism_changed (GtkComboBox *widget,
+                      gpointer user_data)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (user_data);
+	GckMechanismInfo *info;
+	GtkTreeIter iter;
+	GckSlot *slot;
+	guint min;
+	guint max;
+
+	g_free (self->mechanism);
+	self->mechanism = NULL;
+
+	if (gtk_combo_box_get_active_iter (widget, &iter)) {
+		self->mechanism = g_new0 (GckMechanism, 1);
+		gtk_tree_model_get (GTK_TREE_MODEL (self->mechanism_store), &iter,
+		                    MECHANISM_TYPE, &self->mechanism->type, -1);
+
+		slot = seahorse_token_get_slot (self->token);
+		info = gck_slot_get_mechanism_info (slot, self->mechanism->type);
+		g_return_if_fail (info != NULL);
+
+		min = info->min_key_size;
+		max = info->max_key_size;
+
+		if (min < 512 && max >= 512)
+			min = 512;
+		if (max > 16384 && min <= 16384)
+			max = 16384;
+		gtk_spin_button_set_range (self->bits_entry, min, max);
+
+		gck_mechanism_info_free (info);
+	}
+
+	gtk_widget_set_sensitive (GTK_WIDGET (self->bits_entry),
+	                          self->mechanism != NULL);
+
+	update_response (self);
+}
+
+static gint
+on_mechanism_sort (GtkTreeModel *model,
+                   GtkTreeIter *a,
+                   GtkTreeIter *b,
+                   gpointer user_data)
+{
+	gchar *label_a = NULL;
+	gchar *label_b = NULL;
+	gint ret;
+
+	gtk_tree_model_get (model, a, MECHANISM_LABEL, &label_a, -1);
+	gtk_tree_model_get (model, b, MECHANISM_LABEL, &label_b, -1);
+	ret = g_strcmp0 (label_a, label_b);
+	g_free (label_a);
+	g_free (label_b);
+
+	return ret;
+}
+
+static void
+seahorse_pkcs11_generate_constructed (GObject *obj)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (obj);
+	GtkCellRenderer *renderer;
+	GcrCollection *collection;
+	GtkBuilder *builder;
+	const gchar *path;
+	GError *error = NULL;
+	GtkWidget *content;
+	GtkWidget *widget;
+
+	G_OBJECT_CLASS (seahorse_pkcs11_generate_parent_class)->constructed (obj);
+
+	builder = gtk_builder_new ();
+	path = SEAHORSE_UIDIR "/seahorse-pkcs11-generate.xml";
+	gtk_builder_add_from_file (builder, path, &error);
+	if (error != NULL) {
+		g_warning ("couldn't load ui file: %s", path);
+		g_clear_error (&error);
+		g_object_unref (builder);
+		return;
+	}
+
+	gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
+	content = gtk_dialog_get_content_area (GTK_DIALOG (self));
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "pkcs11-generate"));
+	gtk_container_add (GTK_CONTAINER (content), widget);
+	gtk_widget_show (widget);
+
+	self->bits_entry = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "key-bits"));
+	gtk_spin_button_set_range (self->bits_entry, 0, G_MAXINT); /* updated later */
+	gtk_spin_button_set_increments (self->bits_entry, 128, 128);
+	gtk_spin_button_set_value (self->bits_entry, 2048);
+
+	self->label_entry = GTK_ENTRY (gtk_builder_get_object (builder, "key-label"));
+
+	/* The mechanism */
+	self->mechanism_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "key-mechanism"));
+	G_STATIC_ASSERT (MECHANISM_N_COLS == G_N_ELEMENTS (MECHANISM_TYPES));
+	self->mechanism_store = gtk_list_store_newv (MECHANISM_N_COLS, MECHANISM_TYPES);
+	gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (self->mechanism_store),
+	                                         on_mechanism_sort, NULL, NULL);
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->mechanism_store),
+	                                      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+	gtk_combo_box_set_model (self->mechanism_box, GTK_TREE_MODEL (self->mechanism_store));
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->mechanism_box), renderer, TRUE);
+	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->mechanism_box), renderer, "markup", MECHANISM_LABEL);
+	g_signal_connect (self->mechanism_box, "changed", G_CALLBACK (on_mechanism_changed), self);
+
+	/* The tokens */
+	self->token_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "key-token"));
+	collection = seahorse_pkcs11_backend_get_writable_tokens (NULL, CKM_RSA_PKCS_KEY_PAIR_GEN);
+	self->token_model = gcr_collection_model_new (collection, GCR_COLLECTION_MODEL_LIST,
+	                                              "icon", G_TYPE_ICON, "label", G_TYPE_STRING, NULL);
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->token_model), 1, GTK_SORT_ASCENDING);
+	gtk_combo_box_set_model (self->token_box, GTK_TREE_MODEL (self->token_model));
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->token_box), renderer, FALSE);
+	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->token_box), renderer, "gicon", 0);
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->token_box), renderer, TRUE);
+	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->token_box), renderer, "text", 1);
+	g_signal_connect (self->token_box, "changed", G_CALLBACK (on_token_changed), self);
+	if (gcr_collection_get_length (collection) > 0)
+		gtk_combo_box_set_active (self->token_box, 0);
+	g_object_unref (collection);
+
+	/* The buttons */
+	gtk_dialog_add_buttons (GTK_DIALOG (self),
+	                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                        _("Create"), GTK_RESPONSE_OK,
+	                        NULL);
+	gtk_dialog_set_default_response (GTK_DIALOG (self), GTK_RESPONSE_OK);
+
+	update_response (self);
+	g_object_unref (builder);
+}
+
+static void
+seahorse_pkcs11_generate_finalize (GObject *obj)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (obj);
+
+	g_clear_object (&self->token);
+	g_clear_object (&self->token_model);
+
+	g_free (self->mechanism);
+	g_clear_object (&self->mechanism_store);
+
+	g_clear_object (&self->cancellable);
+	gck_attributes_unref (self->pub_attrs);
+	gck_attributes_unref (self->prv_attrs);
+
+	G_OBJECT_CLASS (seahorse_pkcs11_generate_parent_class)->finalize (obj);
+}
+
+static void
+seahorse_pkcs11_generate_response (GtkDialog *dialog,
+                                   gint response_id)
+{
+	SeahorsePkcs11Generate *self = SEAHORSE_PKCS11_GENERATE (dialog);
+	GTlsInteraction *interaction;
+	GtkWindow *parent;
+
+	if (response_id == GTK_RESPONSE_OK) {
+		g_return_if_fail (self->token);
+
+		prepare_generate (self);
+		parent = gtk_window_get_transient_for (GTK_WINDOW (self));
+		interaction = seahorse_interaction_new (parent);
+
+		gck_session_open_async (seahorse_token_get_slot (self->token),
+		                        GCK_SESSION_READ_WRITE | GCK_SESSION_LOGIN_USER,
+		                        interaction, self->cancellable,
+		                        on_generate_open_session, g_object_ref (self));
+
+		seahorse_progress_show (self->cancellable, _("Generating key"), FALSE);
+		g_object_unref (interaction);
+	}
+
+	gtk_widget_hide (GTK_WIDGET (dialog));
+}
+
+static void
+seahorse_pkcs11_generate_class_init (SeahorsePkcs11GenerateClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
+
+	gobject_class->constructed = seahorse_pkcs11_generate_constructed;
+	gobject_class->finalize = seahorse_pkcs11_generate_finalize;
+
+	dialog_class->response = seahorse_pkcs11_generate_response;
+}
+
+void
+seahorse_pkcs11_generate_prompt (GtkWindow *parent)
+{
+	GtkDialog *dialog;
+
+	g_return_if_fail (GTK_IS_WINDOW (parent));
+
+	dialog = g_object_new (SEAHORSE_TYPE_PKCS11_GENERATE,
+	                       "transient-for", parent,
+	                       NULL);
+	g_object_ref_sink (dialog);
+
+	gtk_dialog_run (dialog);
+
+	g_object_unref (dialog);
+}
+
+static void
+on_generate_activate (GtkAction *action,
+                      gpointer user_data)
+{
+	GtkWindow *parent;
+
+	parent = seahorse_action_get_window (action);
+	seahorse_pkcs11_generate_prompt (parent);
+}
+
+static const GtkActionEntry ACTION_ENTRIES[] = {
+	{ "pkcs11-generate-key", GCR_ICON_KEY_PAIR, N_ ("Private key"), "",
+	  N_("Used to request a certificate"), G_CALLBACK (on_generate_activate) }
+};
+
+void
+seahorse_pkcs11_generate_register (void)
+{
+	GtkActionGroup *actions;
+
+	actions = gtk_action_group_new ("pkcs11-generate");
+	gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (actions, ACTION_ENTRIES, G_N_ELEMENTS (ACTION_ENTRIES), NULL);
+	seahorse_registry_register_object (NULL, G_OBJECT (actions), "generator", NULL);
+}
diff --git a/pkcs11/seahorse-pkcs11-generate.h b/pkcs11/seahorse-pkcs11-generate.h
new file mode 100644
index 0000000..5de6b10
--- /dev/null
+++ b/pkcs11/seahorse-pkcs11-generate.h
@@ -0,0 +1,35 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __SEAHORSE_PKCS11_GENERATE_H__
+#define __SEAHORSE_PKCS11_GENERATE_H__
+
+#include <gtk/gtk.h>
+
+#define      SEAHORSE_TYPE_PKCS11_GENERATE        (seahorse_pkcs11_generate_get_type ())
+
+GType        seahorse_pkcs11_generate_get_type    (void) G_GNUC_CONST;
+
+void         seahorse_pkcs11_generate_prompt      (GtkWindow *parent);
+
+void         seahorse_pkcs11_generate_register    (void);
+
+#endif /* __SEAHORSE_PKCS11_GENERATE_H__ */
diff --git a/pkcs11/seahorse-pkcs11-generate.xml b/pkcs11/seahorse-pkcs11-generate.xml
new file mode 100644
index 0000000..873952d
--- /dev/null
+++ b/pkcs11/seahorse-pkcs11-generate.xml
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <object class="GtkHBox" id="pkcs11-generate">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">7</property>
+    <property name="spacing">12</property>
+    <child>
+      <object class="GtkImage" id="key-image">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="yalign">0</property>
+        <property name="pixel_size">48</property>
+        <property name="icon_name">gcr-key-pair</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="label45">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="yalign">0</property>
+            <property name="label" translatable="yes">Create a new private key</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Label:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Stored at:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="key-label">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">â</property>
+                <property name="invisible_char_set">True</property>
+                <property name="activates_default">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBox" id="key-token">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkExpander" id="expander1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <child>
+              <object class="GtkAlignment" id="alignment2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="xscale">0</property>
+                <property name="yscale">0</property>
+                <property name="top_padding">12</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkGrid" id="grid1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">6</property>
+                    <property name="column_spacing">12</property>
+                    <child>
+                      <object class="GtkLabel" id="label49">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Key _Type:</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label50">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Key _Strength (bits):</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="key-mechanism">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSpinButton" id="key-bits">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">â</property>
+                        <property name="invisible_char_set">True</property>
+                        <property name="climb_rate">64</property>
+                        <property name="numeric">True</property>
+                        <property name="activates_default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label48">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;_Advanced key options&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/pkcs11/seahorse-token.c b/pkcs11/seahorse-token.c
index 9f8f5d1..890955f 100644
--- a/pkcs11/seahorse-token.c
+++ b/pkcs11/seahorse-token.c
@@ -59,6 +59,7 @@ struct _SeahorseTokenPrivate {
 	GckSlot *slot;
 	gchar *uri;
 	GckTokenInfo *info;
+	GArray *mechanisms;
 	GckSession *session;
 	GtkActionGroup *actions;
 	GHashTable *object_for_handle;
@@ -77,6 +78,17 @@ G_DEFINE_TYPE_EXTENDED (SeahorseToken, seahorse_token, G_TYPE_OBJECT, 0,
 );
 
 static void
+update_mechanisms (SeahorseToken *self)
+{
+	GArray *mechanisms;
+
+	mechanisms = gck_slot_get_mechanisms (self->pv->slot);
+	if (self->pv->mechanisms != NULL)
+		g_array_unref (self->pv->mechanisms);
+	self->pv->mechanisms = mechanisms;
+}
+
+static void
 update_token_info (SeahorseToken *self)
 {
 	GckTokenInfo *info;
@@ -158,6 +170,9 @@ lookup_id_map (SeahorseToken *self,
 	GPtrArray *objects;
 	guint i;
 
+	if (id == NULL)
+		return NULL;
+
 	objects = g_hash_table_lookup (self->pv->objects_for_id, id);
 	if (objects == NULL)
 		return NULL;
@@ -258,7 +273,7 @@ receive_objects (SeahorseToken *self,
 			object = prev;
 		}
 
-		id = gck_attributes_find (attrs, CKA_ID);
+		id = attrs ? gck_attributes_find (attrs, CKA_ID) : NULL;
 		update_id_map (self, object, id);
 
 		if (SEAHORSE_IS_CERTIFICATE (object)) {
@@ -864,6 +879,31 @@ seahorse_token_get_unlockable (SeahorseToken *self)
 	return !is_session_logged_in (self->pv->session);
 }
 
+GArray *
+seahorse_token_get_mechanisms (SeahorseToken *self)
+{
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), NULL);
+
+	if (!self->pv->mechanisms)
+		update_mechanisms (self);
+
+	return self->pv->mechanisms;
+}
+
+gboolean
+seahorse_token_has_mechanism (SeahorseToken *self,
+                              gulong mechanism)
+{
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), FALSE);
+
+	if (!self->pv->mechanisms)
+		update_mechanisms (self);
+
+	return gck_mechanisms_check (self->pv->mechanisms,
+	                             mechanism,
+	                             GCK_INVALID);
+}
+
 void
 seahorse_token_remove_object (SeahorseToken *self,
                               GckObject *object)
diff --git a/pkcs11/seahorse-token.h b/pkcs11/seahorse-token.h
index 0bb7abe..273479b 100644
--- a/pkcs11/seahorse-token.h
+++ b/pkcs11/seahorse-token.h
@@ -62,6 +62,11 @@ gboolean               seahorse_token_get_lockable      (SeahorseToken *self);
 
 gboolean               seahorse_token_get_unlockable    (SeahorseToken *self);
 
+GArray *               seahorse_token_get_mechanisms    (SeahorseToken *self);
+
+gboolean               seahorse_token_has_mechanism     (SeahorseToken *self,
+                                                         gulong mechanism);
+
 void                   seahorse_token_remove_object     (SeahorseToken *self,
                                                          GckObject *object);
 



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