gnome-keyring r1405 - in trunk: . pkcs11 pkcs11/dot-ssh pkcs11/dot-ssh/tests pkcs11/dot-ssh/tests/test-data pkcs11/gck pkcs11/gck/tests pkcs11/rpc tests



Author: nnielsen
Date: Mon Dec 22 23:31:40 2008
New Revision: 1405
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1405&view=rev

Log:
	* pkcs11/gck/gck-crypto.c:
	* pkcs11/gck/gck-crypto.h:
	* pkcs11/gck/gck-data-der.c:
	* pkcs11/gck/gck-data-openssl.c:
	* pkcs11/gck/gck-data-openssl.h: 
	* pkcs11/gck/tests/unit-test-crypto.c:
	* pkcs11/gck/tests/unit-test-data-openssl.c: Add support for specifying 
	length of password to various PBE algorithms.
	
	* pkcs11/Makefile.am:
	* pkcs11/dot-ssh/*: (added)
	* pkcs11/dot-ssh/tests/*: (added)
	* pkcs11/dot-ssh/tests/test-data/*: (added)
	* pkcs11/gck/gck-data-types.h: 
	* pkcs11/gck/gck-module.h:
	* pkcs11/gck/gck-private-key.c: 
	* pkcs11/gck/gck-util.c:
	* pkcs11/gck/gck-util.h: 
	* tests/gtest.make: 
	* configure.in: Add incomplete but speced dot-ssh PKCS#11 component. 
	 

Added:
   trunk/pkcs11/dot-ssh/   (props changed)
   trunk/pkcs11/dot-ssh/Makefile.am
   trunk/pkcs11/dot-ssh/gck-ssh-module.c
   trunk/pkcs11/dot-ssh/gck-ssh-module.h
   trunk/pkcs11/dot-ssh/gck-ssh-openssh.c
   trunk/pkcs11/dot-ssh/gck-ssh-openssh.h
   trunk/pkcs11/dot-ssh/gck-ssh-private-key.c
   trunk/pkcs11/dot-ssh/gck-ssh-private-key.h
   trunk/pkcs11/dot-ssh/gck-ssh-public-key.c
   trunk/pkcs11/dot-ssh/gck-ssh-public-key.h
   trunk/pkcs11/dot-ssh/tests/   (props changed)
   trunk/pkcs11/dot-ssh/tests/Makefile.am
   trunk/pkcs11/dot-ssh/tests/test-data/
   trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_encrypted
   trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_plain
   trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_test.pub
   trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_encrypted
   trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_plain
   trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_test.pub
   trunk/pkcs11/dot-ssh/tests/unit-test-ssh-openssh.c
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/pkcs11/Makefile.am
   trunk/pkcs11/gck/gck-crypto.c
   trunk/pkcs11/gck/gck-crypto.h
   trunk/pkcs11/gck/gck-data-der.c
   trunk/pkcs11/gck/gck-data-openssl.c
   trunk/pkcs11/gck/gck-data-openssl.h
   trunk/pkcs11/gck/gck-data-types.h
   trunk/pkcs11/gck/gck-module.h
   trunk/pkcs11/gck/gck-private-key.c
   trunk/pkcs11/gck/gck-util.c
   trunk/pkcs11/gck/gck-util.h
   trunk/pkcs11/gck/tests/unit-test-crypto.c
   trunk/pkcs11/gck/tests/unit-test-data-openssl.c
   trunk/pkcs11/rpc/   (props changed)
   trunk/tests/gtest.make

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Dec 22 23:31:40 2008
@@ -513,6 +513,8 @@
 pam/Makefile
 pam/tests/Makefile
 pkcs11/Makefile
+pkcs11/dot-ssh/Makefile
+pkcs11/dot-ssh/tests/Makefile
 pkcs11/gck/Makefile
 pkcs11/gck/tests/Makefile
 pkcs11/rpc/Makefile

Modified: trunk/pkcs11/Makefile.am
==============================================================================
--- trunk/pkcs11/Makefile.am	(original)
+++ trunk/pkcs11/Makefile.am	Mon Dec 22 23:31:40 2008
@@ -41,5 +41,5 @@
 TESTS_DIR = 
 endif
 
-SUBDIRS = . rpc gck $(TESTS_DIR)
+SUBDIRS = . rpc gck dot-ssh $(TESTS_DIR)
 

Added: trunk/pkcs11/dot-ssh/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/Makefile.am	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,35 @@
+
+INCLUDES = \
+	-I$(top_builddir) \
+    	-I$(top_srcdir) \
+    	-I$(top_srcdir)/pkcs11 \
+    	$(GOBJECT_CFLAGS) \
+	$(LIBGCRYPT_CFLAGS) \
+	$(GLIB_CFLAGS)
+	
+# ------------------------------------------------------------------------------
+# The openssh component code
+
+noinst_LTLIBRARIES = \
+	libgck-dot-ssh.la	
+
+libgck_dot_ssh_la_SOURCES = \
+	gck-ssh-module.c gck-ssh-module.h \
+	gck-ssh-openssh.c gck-ssh-openssh.h \
+	gck-ssh-private-key.c gck-ssh-private-key.h \
+	gck-ssh-public-key.c gck-ssh-public-key.h
+
+libgck_dot_ssh_la_LIBADD = \
+	$(GLIB_LIBS) \
+	$(LIBGCRYPT_LIBS) \
+	$(top_builddir)/pkcs11/gck/libgck.la
+	
+# -------------------------------------------------------------------------------
+
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR = 
+endif
+
+SUBDIRS = . $(TESTS_DIR)

Added: trunk/pkcs11/dot-ssh/gck-ssh-module.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-module.c	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,183 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-ssh-module.h"
+#include "gck-ssh-private-key.h"
+#include "gck-ssh-public-key.h"
+
+#include "gck/gck-file-tracker.h"
+
+#include <string.h>
+
+struct _GckSshModule {
+	GObject parent;
+	GckFileTracker *tracker;
+	GHashTable *keys_by_path;
+};
+
+G_DEFINE_TYPE (GckSshModule, gck_ssh_module, GCK_TYPE_MODULE);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static gchar*
+private_path_for_public (const gchar *public_path)
+{
+	gsize length;
+	
+	g_assert (public_path);
+	
+	length = strlen (public_path);
+	if (length > 4 && g_str_equal (public_path + (length - 4), ".pub"))
+		return g_strndup (public_path, length - 4);
+	
+	return NULL;
+}
+
+static void
+file_load (GckFileTracker *tracker, const gchar *path, GckSshModule *self)
+{
+	GckSshPrivateKey *key;
+	GckSshPublicKey *pubkey;
+	gchar *private_path;
+	GckManager *manager;
+	GError *error = NULL;
+	
+	g_return_if_fail (path);
+	g_return_if_fail (GCK_IS_SSH_MODULE (self));
+	
+	private_path = private_path_for_public (path);
+	if (!private_path || !g_file_test (private_path, G_FILE_TEST_IS_REGULAR)) {
+		g_message ("no private key present for public key: %s", path);
+		g_free (private_path);
+		return;
+	}
+	
+	/* Create a key if necessary */
+	key = g_hash_table_lookup (self->keys_by_path, path);
+	if (key == NULL) {
+		key = gck_ssh_private_key_new ();
+		g_hash_table_replace (self->keys_by_path, g_strdup (path), key);
+	}
+	
+	/* Parse the data into the key */
+	if (!gck_ssh_private_key_parse (key, path, private_path, &error)) {
+		g_message ("couldn't parse data: %s: %s", path,
+		           error && error->message ? error->message : "");
+		g_clear_error (&error);
+		
+	/* When successful register with the object manager */
+	} else {
+		manager = gck_module_get_manager (GCK_MODULE (self));
+		
+		/* Make sure the private key has the right manager */
+		if (!gck_object_get_manager (GCK_OBJECT (key))) 
+			gck_manager_register_object (manager, GCK_OBJECT (key));
+		
+		pubkey = gck_ssh_private_key_get_public_key (key);
+		if (!gck_object_get_manager (GCK_OBJECT (pubkey)))
+			gck_manager_register_object (manager, GCK_OBJECT (pubkey));
+	}
+}
+
+static void
+file_remove (GckFileTracker *tracker, const gchar *path, GckSshModule *self)
+{
+	g_return_if_fail (path);
+	g_return_if_fail (GCK_IS_SSH_MODULE (self));
+	g_hash_table_remove (self->keys_by_path, path);
+}
+
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static CK_RV
+gck_ssh_module_real_refresh_token (GckModule *base)
+{
+	GckSshModule *self = GCK_SSH_MODULE (base);
+	gck_file_tracker_refresh (self->tracker, FALSE);
+	return CKR_OK;
+}
+
+static GObject* 
+gck_ssh_module_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GckSshModule *self = GCK_SSH_MODULE (G_OBJECT_CLASS (gck_ssh_module_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);	
+
+
+	
+	return G_OBJECT (self);
+}
+
+static void
+gck_ssh_module_init (GckSshModule *self)
+{
+	self->tracker = gck_file_tracker_new ("~/.ssh", "*.pub", NULL);
+	g_signal_connect (self->tracker, "file-added", G_CALLBACK (file_load), self);
+	g_signal_connect (self->tracker, "file-changed", G_CALLBACK (file_load), self);
+	g_signal_connect (self->tracker, "file-removed", G_CALLBACK (file_remove), self);
+}
+
+static void
+gck_ssh_module_dispose (GObject *obj)
+{
+	GckSshModule *self = GCK_SSH_MODULE (obj);
+	
+	if (self->tracker)
+		g_object_unref (self->tracker);
+	self->tracker = NULL;
+    
+	G_OBJECT_CLASS (gck_ssh_module_parent_class)->dispose (obj);
+}
+
+static void
+gck_ssh_module_finalize (GObject *obj)
+{
+	GckSshModule *self = GCK_SSH_MODULE (obj);
+	
+	g_assert (self->tracker == NULL);
+
+	G_OBJECT_CLASS (gck_ssh_module_parent_class)->finalize (obj);
+}
+
+static void
+gck_ssh_module_class_init (GckSshModuleClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckModuleClass *module_class = GCK_MODULE_CLASS (klass);
+	
+	gobject_class->constructor = gck_ssh_module_constructor;
+	gobject_class->dispose = gck_ssh_module_dispose;
+	gobject_class->finalize = gck_ssh_module_finalize;
+	
+	module_class->refresh_token = gck_ssh_module_real_refresh_token;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+

Added: trunk/pkcs11/dot-ssh/gck-ssh-module.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-module.h	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,45 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_SSH_MODULE_H__
+#define __GCK_SSH_MODULE_H__
+
+#include <glib-object.h>
+
+#include "gck/gck-module.h"
+
+#define GCK_TYPE_SSH_MODULE               (gck_ssh_module_get_type ())
+#define GCK_SSH_MODULE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_SSH_MODULE, GckSshModule))
+#define GCK_SSH_MODULE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_SSH_MODULE, GckSshModuleClass))
+#define GCK_IS_SSH_MODULE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_SSH_MODULE))
+#define GCK_IS_SSH_MODULE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_SSH_MODULE))
+#define GCK_SSH_MODULE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_SSH_MODULE, GckSshModuleClass))
+
+typedef struct _GckSshModule GckSshModule;
+typedef struct _GckSshModuleClass GckSshModuleClass;
+    
+struct _GckSshModuleClass {
+	GckModuleClass parent_class;
+};
+
+GType               gck_ssh_module_get_type               (void);
+
+#endif /* __GCK_SSH_MODULE_H__ */

Added: trunk/pkcs11/dot-ssh/gck-ssh-openssh.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-openssh.c	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,360 @@
+
+#include "gck-ssh-openssh.h"
+
+#include "gck/gck-data-asn1.h"
+#include "gck/gck-data-der.h"
+#include "gck/gck-data-openssl.h"
+#include "gck/gck-data-pem.h"
+#include "gck/gck-data-types.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-secure-memory.h"
+
+typedef struct _ParsePrivate {
+	gcry_sexp_t sexp;
+	gboolean seen;
+	GckDataResult result;
+	const gchar *password;
+	gssize n_password;
+} ParsePrivate;
+
+/* ------------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static int
+keytype_to_algo (const gchar *salgo)
+{
+	g_return_val_if_fail (salgo, 0);
+	if (strcmp (salgo, "ssh-rsa") == 0)
+		return GCRY_PK_RSA;
+	else if (strcmp (salgo, "ssh-dss") == 0)
+		return GCRY_PK_DSA;
+	return 0;
+}
+
+static gboolean
+read_mpi (GkrBuffer *req, gsize *offset, gcry_mpi_t *mpi)
+{
+	const guchar *data;
+	gsize len;
+	gcry_error_t gcry;
+	
+	if (!gkr_buffer_get_byte_array (req, *offset, offset, &data, &len))
+		return FALSE;
+		
+	gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_USG, data, len, NULL);
+	if (gcry)
+		return FALSE;
+		
+	return TRUE;
+}
+
+#define SEXP_PUBLIC_DSA  \
+	"(public-key"    \
+	"  (dsa"         \
+	"    (p %m)"     \
+	"    (q %m)"     \
+	"    (g %m)"     \
+	"    (y %m)))"
+	
+static gboolean
+read_public_dsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp)
+{
+	gcry_mpi_t p, q, g, y;
+	int gcry;
+	
+	if (!read_mpi (req, offset, &p) ||
+	    !read_mpi (req, offset, &q) ||
+	    !read_mpi (req, offset, &g) ||
+	    !read_mpi (req, offset, &y))
+	    	return FALSE;
+
+	gcry = gcry_sexp_build (sexp, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
+	if (gcry) {
+		g_warning ("couldn't parse incoming public DSA key: %s", gcry_strerror (gcry));
+		return FALSE;
+	}
+
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+		
+	return TRUE;
+}
+
+#define SEXP_PUBLIC_RSA  \
+	"(public-key"    \
+	"  (rsa"         \
+	"    (n %m)"     \
+	"    (e %m)))"
+	
+static gboolean
+read_public_rsa (GkrBuffer *req, gsize *offset, gcry_sexp_t *sexp)
+{
+	gcry_mpi_t n, e;
+	int gcry;
+	
+	if (!read_mpi (req, offset, &e) ||
+	    !read_mpi (req, offset, &n))
+	    	return FALSE;
+
+	gcry = gcry_sexp_build (sexp, NULL, SEXP_PUBLIC_RSA, n, e);
+	if (gcry) {
+		g_warning ("couldn't parse incoming public RSA key: %s", gcry_strerror (gcry));
+		return FALSE;
+	}
+
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+		
+	return TRUE;
+}
+
+static gboolean
+read_public (GkrBuffer *req, gsize *offset, gcry_sexp_t *key, int *algo)
+{
+	gboolean ret;
+	gchar *stype;
+	int alg;
+	
+	/* The string algorithm */
+	if (!gkr_buffer_get_string (req, *offset, offset, &stype, (GkrBufferAllocator)g_realloc))
+		return FALSE;
+	
+	alg = keytype_to_algo (stype);
+	g_free (stype);
+	
+	if (!alg) {
+		g_warning ("unsupported algorithm from SSH: %s", stype);
+		return FALSE;
+	}
+	
+	switch (alg) {
+	case GCRY_PK_RSA:
+		ret = read_public_rsa (req, offset, key);
+		break;
+	case GCRY_PK_DSA:
+		ret = read_public_dsa (req, offset, key);
+		break;
+	default:
+		g_assert_not_reached ();
+		return FALSE;
+	}
+	
+	if (!ret) {
+		g_warning ("couldn't read incoming SSH private key");
+		return FALSE;
+	}
+	
+	if (algo)
+		*algo = alg;
+	return TRUE;
+}
+
+static GckDataResult
+load_encrypted_key (const guchar *data, gsize n_data, const gchar *dekinfo,
+                    const gchar *password, gssize n_password, gcry_sexp_t *skey)
+{
+	guchar *decrypted = NULL;
+	gsize n_decrypted = 0;
+	GckDataResult ret;
+	gboolean res;
+	gint length;
+	
+	/* Decrypt, this will result in garble if invalid password */	
+	res = gck_data_openssl_decrypt_block (dekinfo, password, n_password, 
+	                                      data, n_data, &decrypted, &n_decrypted);
+	if (!res)
+		return FALSE;
+			
+	g_assert (decrypted);
+		
+	/* Unpad the DER data */
+	length = gck_data_asn1_element_length (decrypted, n_decrypted);
+	if (length > 0)
+		n_decrypted = length;
+	
+	/* Try to parse */
+	ret = gck_data_der_read_private_key (decrypted, n_decrypted, skey);
+	gkr_secure_free (decrypted);
+
+	if (ret != GCK_DATA_UNRECOGNIZED)
+		return ret;
+	
+	return GCK_DATA_LOCKED;
+}
+
+static void
+parsed_pem_block (GQuark type, const guchar *data, gsize n_data,
+                  GHashTable *headers, gpointer user_data)
+{
+	static GQuark PEM_RSA_PRIVATE_KEY;
+	static GQuark PEM_DSA_PRIVATE_KEY;
+	static gsize quarks_inited = 0;
+	
+	ParsePrivate *ctx = (ParsePrivate*)user_data;
+	const gchar *dekinfo;
+	
+	/* Initialize the first time through */
+	if (g_once_init_enter (&quarks_inited)) {
+		PEM_RSA_PRIVATE_KEY = g_quark_from_static_string ("RSA PRIVATE KEY");
+		PEM_DSA_PRIVATE_KEY = g_quark_from_static_string ("DSA PRIVATE KEY");
+		g_once_init_leave (&quarks_inited, 1);
+	}
+	
+	/* Only handle SSHv2 private keys */
+	if (type != PEM_RSA_PRIVATE_KEY && type != PEM_DSA_PRIVATE_KEY)
+		return;
+
+	ctx->seen = TRUE;
+
+	/* Only parse first key in the file */
+	if (ctx->sexp)
+		return;
+	
+	/* If it's encrypted ... */
+	dekinfo = gck_data_openssl_get_dekinfo (headers);
+	if (dekinfo) {
+		ctx->result = load_encrypted_key (data, n_data, dekinfo, ctx->password, 
+		                                  ctx->n_password, &ctx->sexp);
+		
+	/* not encryted, just load the data */
+	} else {
+		ctx->result = gck_data_der_read_private_key (data, n_data, &ctx->sexp);
+	}
+}
+
+/* ------------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckDataResult
+gck_ssh_openssh_parse_public_key (const guchar *data, gsize n_data,
+                                  gcry_sexp_t *sexp, gchar **comment)
+{
+	GkrBuffer buf;
+	const guchar *at;
+	guchar *decoded;
+	gsize n_decoded;
+	gsize offset;
+	gchar *val;
+	gboolean ret;
+	gint state, algo;
+	guint save;
+
+	g_return_val_if_fail (data, FALSE);
+	g_return_val_if_fail (sexp, FALSE);
+	
+	/* Look for a key line */
+	for (;;) {
+		/* Eat space at the front */
+		while (n_data > 0 && g_ascii_isspace (data[0])) {
+			++data;
+			--n_data;
+		}
+	
+		/* Not a comment or blank line? Then parse... */
+		if (data[0] != '#') 
+			break;
+		
+		/* Skip to the next line */
+		at = memchr (data, '\n', n_data);
+		if (!at) 
+			return GCK_DATA_UNRECOGNIZED;
+		at += 1;
+		n_data -= (at - data);
+		data = at;
+	}
+
+	/* Limit to use only the first line */
+	at = memchr (data, '\n', n_data);
+	if (at != NULL)
+		n_data = at - data;
+	
+	/* Find the first space */
+	at = memchr (data, ' ', n_data);
+	if (!at) {
+		g_message ("SSH public key missing space");
+		return GCK_DATA_UNRECOGNIZED;
+	}
+	
+	/* Parse the key type */
+	val = g_strndup ((gchar*)data, at - data);
+	algo = keytype_to_algo (val);
+	if (!algo) 
+		g_message ("Unsupported or unknown SSH key algorithm: %s", val);
+	g_free (val);
+	if (!algo)
+		return GCK_DATA_UNRECOGNIZED;
+	
+	/* Skip more whitespace */
+	n_data -= (at - data);
+	data = at;
+	while (n_data > 0 && (data[0] == ' ' || data[0] == '\t')) {
+		++data;
+		--n_data;
+	}
+
+	/* Find the next whitespace, or the end */
+	at = memchr (data, ' ', n_data);
+	if (at == NULL)
+		at = data + n_data;
+	
+	/* Decode the base64 key */
+	save = state = 0;
+	decoded = g_malloc (n_data * 3 / 4);
+	n_decoded = g_base64_decode_step ((gchar*)data, n_data, decoded, &state, &save);
+	
+	/* Parse the actual key */
+	gkr_buffer_init_static (&buf, decoded, n_decoded);
+	offset = 0;
+	ret = read_public (&buf, &offset, sexp, NULL);
+	g_free (decoded);
+	if (!ret) {
+		g_message ("failed to parse base64 part of SSH key");
+		return GCK_DATA_FAILURE;
+	}
+
+	/* Skip more whitespace */
+	n_data -= (at - data);
+	data = at;
+	while (n_data > 0 && (data[0] == ' ' || data[0] == '\t')) {
+		++data;
+		--n_data;
+	}
+	
+	/* If there's data left, its the comment */
+	if (comment)
+		*comment = n_data ? g_strndup ((gchar*)data, n_data) : NULL;
+
+	return GCK_DATA_SUCCESS;
+}
+
+GckDataResult
+gck_ssh_openssh_parse_private_key (const guchar *data, gsize n_data, 
+                                   const gchar *password, gssize n_password, 
+                                   gcry_sexp_t *sexp)
+{
+	ParsePrivate ctx;
+	guint num;
+
+	memset (&ctx, 0, sizeof (ctx));
+	ctx.result = FALSE;
+	ctx.seen = FALSE;
+	ctx.sexp = NULL;
+	ctx.password = password;
+	ctx.n_password = n_password;
+	
+	num = gck_data_pem_parse (data, n_data, parsed_pem_block, &ctx);
+
+	/* Didn't find any private key there */
+	if (num == 0 || !ctx.seen) {
+		g_message ("no private keys found in file");
+		return GCK_DATA_UNRECOGNIZED;
+	}
+	
+	*sexp = ctx.sexp;
+	return ctx.result;
+}

Added: trunk/pkcs11/dot-ssh/gck-ssh-openssh.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-openssh.h	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,21 @@
+#ifndef GCKSSHOPENSSH_H_
+#define GCKSSHOPENSSH_H_
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+#include "gck/gck-data-types.h"
+
+GckDataResult         gck_ssh_openssh_parse_public_key                   (const guchar *data, 
+                                                                          gsize n_data,
+                                                                          gcry_sexp_t *sexp, 
+                                                                          gchar **comment);
+
+GckDataResult         gck_ssh_openssh_parse_private_key                  (const guchar *data, 
+                                                                          gsize n_data,
+                                                                          const gchar *password,
+                                                                          gssize n_password,
+                                                                          gcry_sexp_t *sexp);
+
+#endif /* GCKSSHOPENSSH_H_ */

Added: trunk/pkcs11/dot-ssh/gck-ssh-private-key.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-private-key.c	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,318 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-ssh-openssh.h"
+#include "gck-ssh-private-key.h"
+
+#include "gck/gck-manager.h"
+#include "gck/gck-object.h"
+#include "gck/gck-sexp.h"
+#include "gck/gck-util.h"
+
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_LABEL,
+	PROP_PUBLIC_KEY
+};
+
+struct _GckSshPrivateKey {
+	GckPrivateKey parent;
+	
+	GckSshPublicKey *pubkey;
+	gchar *label;
+	guchar *private_data;
+	gsize n_private_data;
+	
+	GckSexp *private_sexp;
+	gboolean is_encrypted;
+};
+
+G_DEFINE_TYPE (GckSshPrivateKey, gck_ssh_private_key, GCK_TYPE_PRIVATE_KEY);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static CK_RV
+unlock_private_key (GckSshPrivateKey *self, const gchar *password, gssize n_password)
+{
+	GckDataResult res;
+	gcry_sexp_t sexp;
+	GckSexp *wrapper;
+
+	g_assert (GCK_IS_SSH_PRIVATE_KEY (self));
+	
+	res = gck_ssh_openssh_parse_private_key (self->private_data, 
+	                                         self->n_private_data, 
+	                                         password, -1, &sexp);
+	
+	switch (res) {
+	case GCK_DATA_LOCKED:
+		self->is_encrypted = TRUE;
+		return CKR_PIN_INCORRECT;
+	case GCK_DATA_FAILURE:
+		g_message ("couldn't parse private SSH key: %s", self->label);
+		return CKR_GENERAL_ERROR;
+	case GCK_DATA_UNRECOGNIZED:
+		g_message ("invalid or unrecognized private SSH key: %s", self->label);
+		return CKR_FUNCTION_FAILED;
+	case GCK_DATA_SUCCESS:
+		break;
+	default:
+		g_assert_not_reached();
+	}
+
+	if (!password || !password[0])
+		self->is_encrypted = FALSE;
+
+	wrapper = gck_sexp_new (sexp);
+	gck_private_key_store_private (GCK_PRIVATE_KEY (self), wrapper, self->is_encrypted ? 1 : 0);
+	gck_sexp_unref (wrapper);
+	
+	return CKR_OK;
+}
+
+static void
+realize_and_take_data (GckSshPrivateKey *self, gcry_sexp_t sexp, gchar *comment, 
+                       guchar *private_data, gsize n_private_data)
+{
+	GckSexp *wrapper;
+	
+	g_assert (GCK_IS_SSH_PRIVATE_KEY (self));
+
+	/* The base public key gets setup. */
+	wrapper = gck_sexp_new (sexp);
+	gck_key_set_base_sexp (GCK_KEY (self), wrapper);
+	gck_key_set_base_sexp (GCK_KEY (self->pubkey), wrapper);
+	gck_sexp_unref (wrapper);
+
+	/* Own the comment */
+	gck_ssh_public_key_set_label (self->pubkey, comment);
+	gck_ssh_private_key_set_label (self, comment);
+	g_free (comment);
+	
+	/* Own the data */
+	g_free (self->private_data);
+	self->private_data = private_data;
+	self->n_private_data = n_private_data;
+	
+	/* Try to parse the private data, and note if it's not actually encrypted */
+	self->is_encrypted = TRUE;
+	if (unlock_private_key (self, "", 0) == CKR_OK) 
+		self->is_encrypted = FALSE;
+	
+	/* Force parsing next time required */
+	gck_private_key_store_private (GCK_PRIVATE_KEY (self), NULL, 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static CK_RV
+gck_ssh_private_key_get_attribute (GckObject *base, CK_ATTRIBUTE_PTR attr)
+{
+	GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (base);
+	
+	switch (attr->type) {
+	case CKA_LABEL:
+		return gck_util_set_string (attr, self->label ? self->label : "");
+	}
+	
+	return GCK_OBJECT_GET_CLASS (base)->get_attribute (base, attr);
+}
+
+static CK_RV
+gck_ssh_private_key_unlock (GckObject *base, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
+{
+	GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (base);
+	return unlock_private_key (self, (const gchar*)pin, n_pin);
+}
+
+static void
+gck_ssh_private_key_init (GckSshPrivateKey *self)
+{
+	self->pubkey = gck_ssh_public_key_new ();
+}
+
+static void
+gck_ssh_private_key_dispose (GObject *obj)
+{
+	GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (obj);
+	
+	if (self->pubkey)
+		g_object_unref (self->pubkey);
+	self->pubkey = NULL;
+    
+	G_OBJECT_CLASS (gck_ssh_private_key_parent_class)->dispose (obj);
+}
+
+static void
+gck_ssh_private_key_finalize (GObject *obj)
+{
+	GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (obj);
+	
+	g_assert (self->pubkey == NULL);
+	
+	g_free (self->private_data);
+	self->private_data = NULL;
+	
+	g_free (self->label);
+	self->label = NULL;
+
+	G_OBJECT_CLASS (gck_ssh_private_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_ssh_private_key_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                           GParamSpec *pspec)
+{
+	GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		gck_ssh_private_key_set_label (self, g_value_get_string (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_ssh_private_key_get_property (GObject *obj, guint prop_id, GValue *value, 
+                           GParamSpec *pspec)
+{
+	GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_set_string (value, gck_ssh_private_key_get_label (self));
+		break;
+	case PROP_PUBLIC_KEY:
+		g_value_set_object (value, gck_ssh_private_key_get_public_key (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_ssh_private_key_class_init (GckSshPrivateKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+	
+	gobject_class->dispose = gck_ssh_private_key_dispose;
+	gobject_class->finalize = gck_ssh_private_key_finalize;
+	gobject_class->set_property = gck_ssh_private_key_set_property;
+	gobject_class->get_property = gck_ssh_private_key_get_property;
+	
+	gck_class->get_attribute = gck_ssh_private_key_get_attribute;
+	gck_class->unlock = gck_ssh_private_key_unlock;
+	
+	g_object_class_install_property (gobject_class, PROP_LABEL,
+	           g_param_spec_string ("label", "Label", "Object Label", 
+	                                "", G_PARAM_READWRITE));
+	
+	g_object_class_install_property (gobject_class, PROP_PUBLIC_KEY,
+	           g_param_spec_object ("public-key", "Public Key", "Public key belonging to this private key", 
+	                                GCK_TYPE_SSH_PUBLIC_KEY, G_PARAM_READABLE));	
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GckSshPrivateKey*
+gck_ssh_private_key_new (void)
+{
+	return g_object_new (GCK_TYPE_SSH_PRIVATE_KEY, NULL);
+}
+
+gboolean
+gck_ssh_private_key_parse (GckSshPrivateKey *self, const gchar *public_path, 
+                           const gchar *private_path, GError **error)
+{
+	guchar *public_data, *private_data;
+	gsize n_public_data, n_private_data;
+	GckDataResult res;
+	gcry_sexp_t sexp;
+	gchar *comment;
+	
+	g_return_val_if_fail (GCK_IS_SSH_PRIVATE_KEY (self), FALSE);
+	g_return_val_if_fail (private_path, FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
+
+	/* Read in the public key */
+	if (!g_file_get_contents (public_path, (gchar**)&public_data, &n_public_data, error))
+		return FALSE;
+	
+	/* Parse it */
+	res = gck_ssh_openssh_parse_public_key (public_data, n_public_data, &sexp, &comment);
+	g_free (public_data);
+	
+	if (res != GCK_DATA_SUCCESS) {
+		g_set_error_literal (error, GCK_DATA_ERROR, res, _("Couldn't parse public SSH key"));
+		return FALSE;
+	}
+
+	/* Read in the private key */
+	if (!g_file_get_contents (private_path, (gchar**)&private_data, &n_private_data, error)) {
+		g_free (comment);
+		gcry_sexp_release (sexp);
+		return FALSE;
+	}
+	
+	if (comment == NULL)
+		comment = g_path_get_basename (private_path);
+	
+	realize_and_take_data (self, sexp, comment, private_data, n_private_data);
+	return TRUE;
+}
+
+const gchar*
+gck_ssh_private_key_get_label (GckSshPrivateKey *self)
+{
+	g_return_val_if_fail (GCK_IS_SSH_PRIVATE_KEY (self), NULL);
+	return self->label;
+}
+
+void
+gck_ssh_private_key_set_label (GckSshPrivateKey *self, const gchar *label)
+{
+	g_return_if_fail (GCK_IS_SSH_PRIVATE_KEY (self));
+	g_free (self->label);
+	self->label = g_strdup (label);
+	g_object_notify (G_OBJECT (self), "label");
+}
+
+GckSshPublicKey*
+gck_ssh_private_key_get_public_key (GckSshPrivateKey *self)
+{
+	g_return_val_if_fail (GCK_IS_SSH_PRIVATE_KEY (self), NULL);
+	return self->pubkey;
+}

Added: trunk/pkcs11/dot-ssh/gck-ssh-private-key.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-private-key.h	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,61 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_SSH_PRIVATE_KEY_H__
+#define __GCK_SSH_PRIVATE_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck-ssh-public-key.h"
+
+#include "gck/gck-private-key.h"
+
+#define GCK_TYPE_SSH_PRIVATE_KEY               (gck_ssh_private_key_get_type ())
+#define GCK_SSH_PRIVATE_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_SSH_PRIVATE_KEY, GckSshPrivateKey))
+#define GCK_SSH_PRIVATE_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_SSH_PRIVATE_KEY, GckSshPrivateKeyClass))
+#define GCK_IS_SSH_PRIVATE_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_SSH_PRIVATE_KEY))
+#define GCK_IS_SSH_PRIVATE_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_SSH_PRIVATE_KEY))
+#define GCK_SSH_PRIVATE_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_SSH_PRIVATE_KEY, GckSshPrivateKeyClass))
+
+typedef struct _GckSshPrivateKey GckSshPrivateKey;
+typedef struct _GckSshPrivateKeyClass GckSshPrivateKeyClass;
+    
+struct _GckSshPrivateKeyClass {
+	GckPrivateKeyClass parent_class;
+};
+
+GType               gck_ssh_private_key_get_type               (void);
+
+GckSshPrivateKey*   gck_ssh_private_key_new                    (void);
+
+gboolean            gck_ssh_private_key_parse                  (GckSshPrivateKey *self,
+                                                                const gchar *public_path,
+                                                                const gchar *private_path,
+                                                                GError **error);
+
+const gchar*        gck_ssh_private_key_get_label              (GckSshPrivateKey *key);
+
+void                gck_ssh_private_key_set_label              (GckSshPrivateKey *key,
+                                                                const gchar *label);
+
+GckSshPublicKey*    gck_ssh_private_key_get_public_key         (GckSshPrivateKey *self);
+
+#endif /* __GCK_SSH_PRIVATE_KEY_H__ */

Added: trunk/pkcs11/dot-ssh/gck-ssh-public-key.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-public-key.c	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,150 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gck-ssh-public-key.h"
+
+#include "gck/gck-object.h"
+#include "gck/gck-util.h"
+
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_LABEL
+};
+
+struct _GckSshPublicKey {
+	GckPublicKey parent;
+	gchar *label;
+};
+
+G_DEFINE_TYPE (GckSshPublicKey, gck_ssh_public_key, GCK_TYPE_PUBLIC_KEY);
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static CK_RV
+gck_ssh_public_key_get_attribute (GckObject *base, CK_ATTRIBUTE_PTR attr)
+{
+	GckSshPublicKey *self = GCK_SSH_PUBLIC_KEY (base);
+	
+	switch (attr->type) {
+	case CKA_LABEL:
+		return gck_util_set_string (attr, self->label ? self->label : "");
+	}
+	
+	return GCK_OBJECT_GET_CLASS (base)->get_attribute (base, attr);
+}
+
+static void
+gck_ssh_public_key_init (GckSshPublicKey *self)
+{
+	
+}
+
+static void
+gck_ssh_public_key_finalize (GObject *obj)
+{
+	GckSshPublicKey *self = GCK_SSH_PUBLIC_KEY (obj);
+	
+	g_free (self->label);
+	self->label = NULL;
+
+	G_OBJECT_CLASS (gck_ssh_public_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_ssh_public_key_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                           GParamSpec *pspec)
+{
+	GckSshPublicKey *self = GCK_SSH_PUBLIC_KEY (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		gck_ssh_public_key_set_label (self, g_value_get_string (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_ssh_public_key_get_property (GObject *obj, guint prop_id, GValue *value, 
+                           GParamSpec *pspec)
+{
+	GckSshPublicKey *self = GCK_SSH_PUBLIC_KEY (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_set_string (value, gck_ssh_public_key_get_label (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gck_ssh_public_key_class_init (GckSshPublicKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+    
+	gobject_class->finalize = gck_ssh_public_key_finalize;
+	gobject_class->set_property = gck_ssh_public_key_set_property;
+	gobject_class->get_property = gck_ssh_public_key_get_property;
+	
+	gck_class->get_attribute = gck_ssh_public_key_get_attribute;
+	
+	g_object_class_install_property (gobject_class, PROP_LABEL,
+	           g_param_spec_string ("label", "Label", "Object Label", 
+	                                "", G_PARAM_READWRITE));	
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GckSshPublicKey*
+gck_ssh_public_key_new (void)
+{
+	return g_object_new (GCK_TYPE_SSH_PUBLIC_KEY, NULL);
+}
+
+const gchar*
+gck_ssh_public_key_get_label (GckSshPublicKey *self)
+{
+	g_return_val_if_fail (GCK_IS_SSH_PUBLIC_KEY (self), NULL);
+	return self->label;
+}
+
+void
+gck_ssh_public_key_set_label (GckSshPublicKey *self, const gchar *label)
+{
+	g_return_if_fail (GCK_IS_SSH_PUBLIC_KEY (self));
+	g_free (self->label);
+	self->label = g_strdup (label);
+	g_object_notify (G_OBJECT (self), "label");
+}

Added: trunk/pkcs11/dot-ssh/gck-ssh-public-key.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/gck-ssh-public-key.h	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,52 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCK_SSH_PUBLIC_KEY_H__
+#define __GCK_SSH_PUBLIC_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck/gck-public-key.h"
+
+#define GCK_TYPE_SSH_PUBLIC_KEY               (gck_ssh_public_key_get_type ())
+#define GCK_SSH_PUBLIC_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_SSH_PUBLIC_KEY, GckSshPublicKey))
+#define GCK_SSH_PUBLIC_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_SSH_PUBLIC_KEY, GckSshPublicKeyClass))
+#define GCK_IS_SSH_PUBLIC_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_SSH_PUBLIC_KEY))
+#define GCK_IS_SSH_PUBLIC_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_SSH_PUBLIC_KEY))
+#define GCK_SSH_PUBLIC_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_SSH_PUBLIC_KEY, GckSshPublicKeyClass))
+
+typedef struct _GckSshPublicKey GckSshPublicKey;
+typedef struct _GckSshPublicKeyClass GckSshPublicKeyClass;
+    
+struct _GckSshPublicKeyClass {
+	GckPublicKeyClass parent_class;
+};
+
+GType               gck_ssh_public_key_get_type               (void);
+
+GckSshPublicKey*    gck_ssh_public_key_new                    (void);
+
+const gchar*        gck_ssh_public_key_get_label              (GckSshPublicKey *key);
+
+void                gck_ssh_public_key_set_label              (GckSshPublicKey *key,
+                                                                const gchar *label);
+
+#endif /* __GCK_SSH_PUBLIC_KEY_H__ */

Added: trunk/pkcs11/dot-ssh/tests/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/Makefile.am	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,11 @@
+UNIT_AUTO = \
+	unit-test-ssh-openssh.c 
+
+UNIT_PROMPT = 
+
+UNIT_LIBS =  \
+	$(top_builddir)/pkcs11/dot-ssh/libgck-dot-ssh.la \
+	$(top_builddir)/pkcs11/gck/libgck.la \
+	$(top_builddir)/common/libgkr-module-common.la
+
+include $(top_srcdir)/tests/gtest.make

Added: trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_encrypted
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_encrypted	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,15 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,1ED7C6189634877B
+
+lex6pFMAspyvnqSktXA1NX/x80/Ebb9BGFaIcJAPvLduCrDR02fgwc3oE+dwSwwe
+PXZ8vJK8+AP+Z8Rkedya/3OT4vaAuSENZFCfJA+P6lXglVQplA57R4U5/P9580Ee
+l/VTumnh5Gz84hJ5TuEspDOLrq8atkc31qFbEJ+zjMLygGNGbIOzecLou2pBt1Ol
+ncx1MPIznoJl2b1NQt7rgPpcbqzCHo+/qgLgvGs7osIg8xzzp+E2ifWuwCnY4NmW
+dxLRABi4I97q7kShH7OblBQLKxDreg28sojJQ0h0y0fd6xVcoscFCvfanFh8xx/D
+rI+JV3HCRCrlB9YS6U3zB5vpbc1UQ1EaE4AxSmrSLdKsvrPGc7M+grwy/DjYerqO
+WGwFWnz/OrlXruJG9Nwyltq/YmXAxFGoSWrunkm42xUxYs8RElddQOFC0ZyfVWOi
+IOS2Bv2HkNW+lMTRoR/RIbDc90wzO0HL0Xx4v6LYSbVBZIcaOJU+stoNLeE8Fu53
+G47YU+Fd7WswdlIdXtrPjyyiWapf6+xNdhRrqB+40JJQRi2mL1NyYZ2bZkjEd0Or
+DsfFH/+DlZrjEdlqWTK2ow==
+-----END DSA PRIVATE KEY-----

Added: trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_plain
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_plain	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQDCyZij6148cb6Gp2XazVJr+zrcfSkbN1MyeR5hCgACTqcn1D4R
+huf79uWe7lvyYuPyXNedfde0iFP7Ff9k1T9i3thyYjs1scdwpbqxnAVnmN4SNv/v
+fFXPp6w0EDNqmAOwg+Pqwue7juiPVJyPBcsSPZZKTOMDCS/2fVibFCXgswIVAOW6
+ngNCg6d4Cn+GHQtEbNVtZpRdAoGAP2LhEH+zUCYri0xi32l9bMnlqDCBdw2zOMbe
+G2XDRt40W4ObiE1+PPNp/CDFuYrOjD4s7Cl4s/U+iop4DKsPcLwbdr3CoWE6hEuO
+dH0jkzcvt8kZ5Ymtm3OiqEW2ARi8rUwVJ9+bRbkfRerNrDeH/PQzwCWf7Lzp9lPT
+NVjCDtsCgYANW+HtuJWVmfXRRDJ1goMK+GXixDvBLBbFSDf74kYInt3vUBm4MKpr
+HbmC27TLRymb6IOH1ENpYT3MffZJusQTqqZJKPba5nwLvPP9lzN60bJAtqiWUsqf
+wHEh6Jx+qoMggm8i6ogJJO2zDlki5Twf1ilN+tinHdOL/2CmPPRMgAIVALKfUS61
+xqFTOY5fG1+rLwlPGvL9
+-----END DSA PRIVATE KEY-----

Added: trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_test.pub
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/test-data/id_dsa_test.pub	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,7 @@
+# A comment should be ignored
+
+# Blank lines should be ignored
+
+ssh-dss AAAAB3NzaC1kc3MAAACBANHNmw2YHEodUj4Ae27i8Rm8uoLnpS68QEiCJx8bv9P1o0AaD0w55sH+TBzlo7vtAEDlAzIOBY3PMpy5WarELTIeXmFPzKfHL8tuxMbOPaN/wDkDZNnJZsqlyRwlQKStPcAlvLBNuMjA53u2ndMTVghtUHXETQzwxKhXf7TmvfLBAAAAFQDnF/Y8MgFCP0PpRC5ZAQo1dyDEwwAAAIEAr4iOpTeZx8i1QgQpRl+dmbBAtHTXbPiophzNJBge9lixqF0T3egN2B9wGGnumIXmnst9RPPjuu+cHCLfxhXHzLlW8MLwoiF6ZQOx9M8WcfWIl5oiGyr2e969woRf5OcMGQPOQBdws6MEtemRqq5gu6dqDqVl3xfhSZSP9LpqAI8AAACAUjiuQ3qGErsCz++qd0qrR++QA185XGXAPZqQEHcr4iKSlO17hSUYA03kOWtDaeRtJOlxjIjl9iLo3juKGFgxUfo2StScOSO2saTWFGjA4MybHCK1+mIYXRcYrq314yK2Tmbql/UGDWpcCCGXLWpSFHTaXTbJjPd6VL+TO9/8tFk= A public key comment
+
+# blah blah

Added: trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_encrypted
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_encrypted	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,C7CA72E4022D0E83
+
+me0oewaJEzC9jiS1EaEN1dgXwc6QpVa9YeZLOmuhWbKhJI7B4eB7ZzdCRZv07wKv
+kCSkM+/rk6Env7QjkRhREF2Uc1jGwZAh5SttP/eGlWe4tcJ0o246rNgtPmyrlmh4
+7jESkZICnv7kv9nam4W0GU/4UHTGZsx4z6l0XUnbI5mDwUC4QL7mF9Bu3tZ3+hlY
+V4Pr7OklILzopGuoaYaJABhbu/EtU3R8+g9gXJZFkLJUo41Q53BjBlZb1XEKSBE/
+3TL+sDVklBOZlqgIiBnN7buGeC/0VFzmworpMvti1SIBtfKCuYGYcrqoeUmP8+CK
+lAOpfFGWuh89YpVsWG57pJg6YJo8SrqwmUO0ksv3SA2Lf4hoecX3Ikp6vNKYlZ27
+uKWtmWV79gtsOKARh2v72ZFChRS6AQFkU1ZMA56rKEaW/Mvlm/7HF9G4k7SEftR1
+r06FUKp5uUCbvWOfyYM/69HdB8aZROU24zUPkYu49kZ/QCl7q7LxG+ODJIybyklR
+RxZVO0qcb14umRP0iC+9jNw3J/hECS6JzHW7NbCplzi/AEbXZGUrhfzpri3CTs81
+l9WSywbZINUyesYO4TfttfmCgBuLRc0x2C/wrn8MG09Gl7c2aw2pxhaMPGF3j/G8
+shV7FwTGsKm8G+eMSiFXkm58Biz/nAITimAqe36VsmkcqjAuX0YVAiLVkux9YmQ2
+5hmCoBaZIx88YGgCwsigwPQPGQrXlZinlFfYluG6trA42pl2BD/6U/AJEZ8RUsD0
+OshlvRxxR0/zCqMufRWxBb1BUftglKunfiF6iHgTshIoOUmvLblzaEDB8Jf5UMS1
+tZMH0RQSLH3gQ+kp7/2mW2jGbdIhusru729yykb/9iinoGMEgdsfFr62nDj5zPYb
+kltEUwjVWnuL/O/38exZjrIZkf1uaFkjLXqrHIz3MuoHSoVd/AVBeEU4BvKO4aoM
+mgcT/Nc+jNWhOOewDtvtYxcPjrvmg69huLG0XoCgQ8P2GQJD2rSVc2MTe3hqmJj8
+SKqSUdlq4Sb+8K/hh++gCQkrJb5q7zIdXxULA7xf8PD2yhrVgO/h9mzaDxR77zBJ
+lab2dSxEH9vdGQKqGT6ZndEZo6Gopn2pXtn7bYVN2K0GojYa2MiLNbuhqxtZvg5Z
+Y49acItEd49objc40IU6WAAwz5w6jl6lybTq6EiNSMsmtekugUwyFQCOpTfYdOwZ
+9zrbmzwiWWAiQQTYuPESS1FpQEvAilzoSmwmbNkaAbMZfguX429+cSW1Kdu0/AWq
+SGx7AFpZpbKLd7hdKy25ZRIyRqu0goTsqA/r28faLKhjhKMF2Dl+Pgtkny7t/k1Z
+ZJXGmt++mHIck1UvGZR37thqpqd5IF9e96Pos1nQPfkV3cxXOT6mMOf9F3yCYW6d
+VclJPaM0lTEobbt2q/cDIM86Mo7G3cYHtfe7O+ard5Uhz+KVXhczduXeiwR4XNmP
+xQj/mgGTGCZIEWMJ32576B/vjEThY1RkA/wvdiMmV4gskXBbu/rhcX/RX51yBalP
+FU0DCN56t7vrXacEcdilMJIWLFZiqQCvYFHigNhwVsfBhNZHDxRODg==
+-----END RSA PRIVATE KEY-----

Added: trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_plain
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_plain	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAoD6VKqkhay6pKHSRjAGWWfFPU8xfsi2gnOwP/B1UHDoztx3c
+zhO+py/fTlhCnSP1jsjkrVIZcnzah2fUNFFRgS4+jROBtvbgHsS72V1E6+ZogV+m
+BJWWAhw0iPrmQ3Kvm38D3PByo5Y7yKO5kIG2LloYLjosJ5F4sx2xh0uz2wXNtnY1
+b5xhe2+VEksm9OB+FXaUkZC2fQrTNo8ZGFJQSFd8kUhIfbUDJmlYuZ+vvHM+A3Lc
+9rHyW4IPaRyxFQciRmb+ZQqU2uSdOXAhg17lskuX/q8yCI5Hy5eDicC222oUMdJT
+tYgwX4dQCU8TICWhxb3x4RCV+g7D99+tkIvv+wIBIwKCAQEAm6qCRrLtQ4xpz4cu
+TX3ig0Ivzb84Y/HPOVpYq8S4G2u9NYq5PTfAhScwsoGfy9nJ+GthzPCrAYCZxV2M
+UBR7D8aF6CGT85C8dakrgrJgNZ3/HpduExT4H06Zbx+d2x7zu5/1H8UBpjorcnMp
+SoyiWOnOWMrLzqqSghzYV4teQnkhDmMTDgP/L39k9oLh/gvDHkxQET/IirrM3iT3
+rpZsXjsA+vAOrDrrsauPP9uAswaRGOH1O+xdAc/QH6/j2RK6ew/uICl0V9xYddSw
+9LSkk0gre2sdd7zz/r2t1oMFFsq+MaQ5Uynz0zmwpe/wyQjWY1ILy/wcIdOpLyOS
+PUaMSwKBgQDMULEsX+QChX3Od9gnwfbu4it7KYOV8V495al1YsaEyZcmcPQNKGrG
+iHyjDTWjj9w0THhrzF2ZfkWw3+N3SHfYqRx0+bzMgttEEJbaACOqBJPMmOwmi30I
+9ILcmsSMyOk+W9bHKPQ4OjwIVruiyvsFoLfhcFm0hispibWCKnlhUQKBgQDIx+aT
+kFnnVBvPnLAHgDfN32X0KR5Kk3PRe0cdNoeJHb/VHgLC0SuzZwdl+bzLdEyDaKht
+MGiPtblEhrjeTvwCHpwFOyMb33lYc1En8L2DNDjL0CASzRoHbvcKkin/L78wKmkV
+TY5uFyZ7Q/5S0YNlGSKL02+XURE/F/4FzKRJiwKBgQC6zW7JfD4uMOgNOl86SvBl
+YRHPsO1V4/5kejSIlNLCjGzv8j436nBAfMm5pa1iV6TCGgezA/3OKk5Yki8N+R0d
+3HHKCOchYbKHX5/dQfS4s7pUqRJsYkZulmkENbsEX+sxsw2C4511PI6oidAfz4Zr
+i6DOHZPYQCd2b0bdaKl9iwKBgQCD8RPdUDsUW9fC8fAE7duHSall7yKIx0wb8ezn
+T7gm56nycs6dR6Bf8z9gRQcJWw21cKkxz1qnlKzyhGrbOzfkIr5MlJNqFoLw+1KW
+luLv0dwuKa6tRPPY/8bpsIH/dyXd0roVUDkGhD3b+Xs9vOFREIRqg6EaSzc4FxSk
+ua3J7QKBgBVAzKSD3ya+VYKFD3E8GaiLQoClJF2t9Zkzr3yyJ657CwugA/2uU2/x
+3YNU3vK9hyypTXulbtteifRceSLDxEBQ67f0F3gvBqU6ZU2FmD7YTTv82Jvl0Ue2
+49ouxRjON9nXmr+6qe/yr5vIRlcRjKlfaIxDL7V6OTgwedUwqCuY
+-----END RSA PRIVATE KEY-----

Added: trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_test.pub
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/test-data/id_rsa_test.pub	Mon Dec 22 23:31:40 2008
@@ -0,0 +1 @@
+ssh-rsa   AAAAB3NzaC1yc2EAAAABIwAAAQEAoD6VKqkhay6pKHSRjAGWWfFPU8xfsi2gnOwP/B1UHDoztx3czhO+py/fTlhCnSP1jsjkrVIZcnzah2fUNFFRgS4+jROBtvbgHsS72V1E6+ZogV+mBJWWAhw0iPrmQ3Kvm38D3PByo5Y7yKO5kIG2LloYLjosJ5F4sx2xh0uz2wXNtnY1b5xhe2+VEksm9OB+FXaUkZC2fQrTNo8ZGFJQSFd8kUhIfbUDJmlYuZ+vvHM+A3Lc9rHyW4IPaRyxFQciRmb+ZQqU2uSdOXAhg17lskuX/q8yCI5Hy5eDicC222oUMdJTtYgwX4dQCU8TICWhxb3x4RCV+g7D99+tkIvv+w==   A public key comment

Added: trunk/pkcs11/dot-ssh/tests/unit-test-ssh-openssh.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/dot-ssh/tests/unit-test-ssh-openssh.c	Mon Dec 22 23:31:40 2008
@@ -0,0 +1,130 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-ssh-openssh.c: Test OpenSSH parsing
+
+   Copyright (C) 2008 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "run-auto-test.h"
+
+#include "gck-ssh-openssh.h"
+
+#include "gck/gck-crypto.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static const gchar *PRIVATE_FILES[] = {
+	"id_rsa_encrypted",
+	"id_rsa_plain",
+	"id_dsa_encrypted",
+	"id_dsa_plain"
+};
+
+static const gchar *PUBLIC_FILES[] = {
+	"id_rsa_test.pub",
+	"id_dsa_test.pub"
+};
+
+#define COMMENT "A public key comment"
+
+static void
+read_file (const gchar *filename, guchar **contents, gsize *len)
+{
+	gchar *path;
+	gboolean ret;
+	
+	path = g_build_filename (g_get_current_dir (), "test-data", filename, NULL);
+	ret = g_file_get_contents (path, (gchar**)contents, len, NULL);
+	g_assert ("couldn't read in file" && ret);
+	
+	g_free (path);
+}
+
+DEFINE_TEST(parse_public)
+{
+	gcry_sexp_t sexp;
+	gchar *comment;
+	guchar *data;
+	gsize n_data;
+	int algorithm;
+	gboolean is_private;
+	guint i;
+	GckDataResult res;
+	
+	
+	for (i = 0; i < G_N_ELEMENTS (PUBLIC_FILES); ++i) {
+		
+		read_file (PUBLIC_FILES[i], &data, &n_data);
+		
+		res = gck_ssh_openssh_parse_public_key (data, n_data, &sexp, &comment);
+		if (res != GCK_DATA_SUCCESS) {
+			g_warning ("couldn't parse public key: %s", PUBLIC_FILES[i]);
+			g_assert_cmpint (res, ==, GCK_DATA_SUCCESS);
+		}
+		
+		if (!gck_crypto_sexp_parse_key (sexp, &algorithm, &is_private, NULL))
+			g_assert_not_reached ();
+		
+		g_assert_cmpstr (comment, ==, COMMENT);
+		g_assert_cmpint (algorithm, !=, 0);
+		g_assert (!is_private);
+		
+		g_free (data);
+		g_free (comment);
+		gcry_sexp_release (sexp);
+	}
+}
+
+DEFINE_TEST(parse_private)
+{
+	gcry_sexp_t sexp;
+	guchar *data;
+	gsize n_data;
+	int algorithm;
+	gboolean is_private;
+	guint i;
+	GckDataResult res;
+	
+	
+	for (i = 0; i < G_N_ELEMENTS (PRIVATE_FILES); ++i) {
+		
+		read_file (PRIVATE_FILES[i], &data, &n_data);
+		
+		res = gck_ssh_openssh_parse_private_key (data, n_data, "password", 8, &sexp);
+		if (res != GCK_DATA_SUCCESS) {
+			g_warning ("couldn't parse private key: %s", PRIVATE_FILES[i]);
+			g_assert_cmpint (res, ==, GCK_DATA_SUCCESS);
+		}
+		
+		if (!gck_crypto_sexp_parse_key (sexp, &algorithm, &is_private, NULL))
+			g_assert_not_reached ();
+		
+		g_assert_cmpint (algorithm, !=, 0);
+		g_assert (is_private);
+		
+		g_free (data);
+		gcry_sexp_release (sexp);
+	}
+}
\ No newline at end of file

Modified: trunk/pkcs11/gck/gck-crypto.c
==============================================================================
--- trunk/pkcs11/gck/gck-crypto.c	(original)
+++ trunk/pkcs11/gck/gck-crypto.c	Mon Dec 22 23:31:40 2008
@@ -895,9 +895,9 @@
 
 gboolean
 gck_crypto_symkey_generate_simple (int cipher_algo, int hash_algo, 
-                                   const gchar *password, const guchar *salt, 
-                                   gsize n_salt, int iterations, guchar **key, 
-                                   guchar **iv)
+                                   const gchar *password, gssize n_password, 
+                                   const guchar *salt, gsize n_salt, int iterations, 
+                                   guchar **key, guchar **iv)
 {
 	gcry_md_hd_t mdh;
 	gcry_error_t gcry;
@@ -913,6 +913,11 @@
 
 	g_return_val_if_fail (iterations >= 1, FALSE);
 	
+	if (!password)
+		n_password = 0;
+	if (n_password == -1)
+		n_password = strlen (password);
+	
 	/* 
 	 * If cipher algo needs more bytes than hash algo has available
 	 * then the entire hashing process is done again (with the previous
@@ -952,7 +957,7 @@
 			gcry_md_write (mdh, digest, n_digest);
 
 		if (password)
-			gcry_md_write (mdh, password, strlen (password));
+			gcry_md_write (mdh, password, n_password);
 		if (salt && n_salt)
 			gcry_md_write (mdh, salt, n_salt);
 		gcry_md_final (mdh);
@@ -996,7 +1001,7 @@
 
 gboolean
 gck_crypto_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, 
-                                const guchar *salt, gsize n_salt, int iterations, 
+                                gssize n_password, const guchar *salt, gsize n_salt, int iterations, 
                                 guchar **key, guchar **iv)
 {
 	gcry_md_hd_t mdh;
@@ -1011,6 +1016,11 @@
 
 	g_return_val_if_fail (iterations >= 1, FALSE);
 	
+	if (!password)
+		n_password = 0;
+	if (n_password == -1)
+		n_password = strlen (password);
+	
 	/* 
 	 * We only do one pass here.
 	 * 
@@ -1051,7 +1061,7 @@
 		*iv = g_new0 (guchar, needed_iv);
 
 	if (password)
-		gcry_md_write (mdh, password, strlen (password));
+		gcry_md_write (mdh, password, n_password);
 	if (salt && n_salt)
 		gcry_md_write (mdh, salt, n_salt);
 	gcry_md_final (mdh);
@@ -1082,11 +1092,12 @@
 
 static gboolean
 generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, 
-                 const guchar *salt, gsize n_salt, int iterations,
-                 guchar *output, gsize n_output)
+                 gssize n_password, const guchar *salt, gsize n_salt, 
+                 int iterations, guchar *output, gsize n_output)
 {
 	gcry_mpi_t num_b1, num_ij;
 	guchar *hash, *buf_i, *buf_b;
+	const gchar *end_password;
 	gcry_md_hd_t mdh;
 	const gchar *p2;
 	guchar *p;
@@ -1099,6 +1110,13 @@
 	n_hash = gcry_md_get_algo_dlen (hash_algo);
 	g_return_val_if_fail (n_hash > 0, FALSE);
 	
+	if (!utf8_password)
+		n_password = 0;
+	if (n_password == -1) 
+		end_password = utf8_password + strlen (utf8_password);
+	else
+		end_password = utf8_password + n_password;
+	
 	gcry = gcry_md_open (&mdh, hash_algo, 0);
 	if (gcry) {
 		g_warning ("couldn't create '%s' hash context: %s", 
@@ -1126,13 +1144,21 @@
 	if (utf8_password) {
 		p2 = utf8_password;
 		for (i = 0; i < 64; i += 2) {
-			unich = *p2 ? g_utf8_get_char (p2) : 0;
-			*(p++) = (unich & 0xFF00) >> 8;
-			*(p++) = (unich & 0xFF);
-			if (*p2) /* Loop back to beginning if more bytes are needed */
+			
+			/* Get a character from the string */
+			if (p2 < end_password) {
+				unich = g_utf8_get_char (p2);
 				p2 = g_utf8_next_char (p2);
-			else
+
+			/* Get zero null terminator, and loop back to beginning */
+			} else {
+				unich = 0;
 				p2 = utf8_password;
+			}
+
+			/* Encode the bytes received */
+			*(p++) = (unich & 0xFF00) >> 8;
+			*(p++) = (unich & 0xFF);
 		}
 	} else {
 		memset (p, 0, 64);
@@ -1195,7 +1221,7 @@
 
 gboolean
 gck_crypto_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password, 
-                                   const guchar *salt, gsize n_salt,
+                                   gssize n_password, const guchar *salt, gsize n_salt,
                                    int iterations, guchar **key, guchar **iv)
 {
 	gsize n_block, n_key;
@@ -1208,7 +1234,7 @@
 	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
 	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
 	
-	if (password && !g_utf8_validate (password, -1, NULL)) {
+	if (password && !g_utf8_validate (password, n_password, NULL)) {
 		g_warning ("invalid non-UTF8 password");
 		g_return_val_if_reached (FALSE);
 	}
@@ -1222,7 +1248,7 @@
 	if (key) {
 		*key = gkr_secure_alloc (n_key);
 		g_return_val_if_fail (*key != NULL, FALSE);
-		ret = generate_pkcs12 (hash_algo, 1, password, salt, n_salt, 
+		ret = generate_pkcs12 (hash_algo, 1, password, n_password, salt, n_salt, 
 		                       iterations, *key, n_key);
 	} 
 	
@@ -1230,7 +1256,7 @@
 	if (ret && iv) {
 		if (n_block > 1) {
 			*iv = g_malloc (n_block);
-			ret = generate_pkcs12 (hash_algo, 2, password, salt, n_salt, 
+			ret = generate_pkcs12 (hash_algo, 2, password, n_password, salt, n_salt, 
 			                       iterations, *iv, n_block);
 		} else {
 			*iv = NULL;
@@ -1326,11 +1352,11 @@
 
 gboolean
 gck_crypto_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo, 
-                                   const gchar *password, const guchar *salt, 
-                                   gsize n_salt, int iterations, 
+                                   const gchar *password, gssize n_password, 
+                                   const guchar *salt, gsize n_salt, int iterations, 
                                    guchar **key, guchar **iv)
 {
-	gsize n_key, n_block, n_password;
+	gsize n_key, n_block;
 	gboolean ret = TRUE;
 	
 	g_return_val_if_fail (hash_algo, FALSE);
@@ -1344,8 +1370,11 @@
 		*key = NULL;
 	if (iv)
 		*iv = NULL;
-		
-	n_password = password ? strlen (password) : 0;
+	
+	if (!password)
+		n_password = 0;
+	if (n_password == -1)
+		n_password = strlen (password);
 	
 	/* Generate us an key */
 	if (key) {

Modified: trunk/pkcs11/gck/gck-crypto.h
==============================================================================
--- trunk/pkcs11/gck/gck-crypto.h	(original)
+++ trunk/pkcs11/gck/gck-crypto.h	Mon Dec 22 23:31:40 2008
@@ -162,6 +162,7 @@
 gboolean                 gck_crypto_symkey_generate_simple             (int cipher_algo, 
                                                                         int hash_algo, 
                                                                         const gchar *password, 
+                                                                        gssize n_password,
                                                                         const guchar *salt, 
                                                                         gsize n_salt, 
                                                                         int iterations, 
@@ -170,7 +171,8 @@
 
 gboolean                 gck_crypto_symkey_generate_pbe                (int cipher_algo, 
                                                                         int hash_algo, 
-                                                                        const gchar *password, 
+                                                                        const gchar *password,
+                                                                        gssize n_password,
                                                                         const guchar *salt, 
                                                                         gsize n_salt, 
                                                                         int iterations, 
@@ -179,7 +181,8 @@
 
 gboolean                 gck_crypto_symkey_generate_pkcs12             (int cipher_algo, 
                                                                         int hash_algo, 
-                                                                        const gchar *password, 
+                                                                        const gchar *password,
+                                                                        gssize n_password,
                                                                         const guchar *salt, 
                                                                         gsize n_salt,
                                                                         int iterations, 
@@ -188,7 +191,8 @@
 
 gboolean                 gck_crypto_symkey_generate_pbkdf2             (int cipher_algo, 
                                                                         int hash_algo, 
-                                                                        const gchar *password, 
+                                                                        const gchar *password,
+                                                                        gssize n_password,
                                                                         const guchar *salt, 
                                                                         gsize n_salt, 
                                                                         int iterations, 

Modified: trunk/pkcs11/gck/gck-data-der.c
==============================================================================
--- trunk/pkcs11/gck/gck-data-der.c	(original)
+++ trunk/pkcs11/gck/gck-data-der.c	Mon Dec 22 23:31:40 2008
@@ -106,7 +106,7 @@
 	}
 }
 
-#endif UNTESTED_CODE
+#endif /* UNTESTED_CODE */
 
 /* -----------------------------------------------------------------------------
  * KEY PARSING

Modified: trunk/pkcs11/gck/gck-data-openssl.c
==============================================================================
--- trunk/pkcs11/gck/gck-data-openssl.c	(original)
+++ trunk/pkcs11/gck/gck-data-openssl.c	Mon Dec 22 23:31:40 2008
@@ -279,7 +279,7 @@
 
 GckDataResult
 gck_data_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, 
-                                const guchar *data, gsize n_data, 
+                                gssize n_password, const guchar *data, gsize n_data, 
                                 guchar **decrypted, gsize *n_decrypted)
 {
 	gcry_cipher_hd_t ch;
@@ -299,7 +299,7 @@
 	
 	/* IV is already set from the DEK info */
 	if (!gck_crypto_symkey_generate_simple (algo, GCRY_MD_MD5, password, 
-	                                        iv, 8, 1, &key, NULL)) {
+	                                        n_password, iv, 8, 1, &key, NULL)) {
 		g_free (iv);
 		return GCK_DATA_FAILURE;
 	}
@@ -334,7 +334,7 @@
 
 gboolean
 gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, 
-                                const guchar *data, gsize n_data,
+                                gssize n_password, const guchar *data, gsize n_data,
                                 guchar **encrypted, gsize *n_encrypted)
 {
 	gsize n_overflow, n_batch, n_padding;
@@ -356,7 +356,7 @@
 	
 	/* IV is already set from the DEK info */
 	if (!gck_crypto_symkey_generate_simple (algo, GCRY_MD_MD5, password, 
-	                                        iv, 8, 1, &key, NULL))
+	                                        n_password, iv, 8, 1, &key, NULL))
 		g_return_val_if_reached (FALSE);
 	
 	gcry = gcry_cipher_open (&ch, algo, mode, 0);

Modified: trunk/pkcs11/gck/gck-data-openssl.h
==============================================================================
--- trunk/pkcs11/gck/gck-data-openssl.h	(original)
+++ trunk/pkcs11/gck/gck-data-openssl.h	Mon Dec 22 23:31:40 2008
@@ -29,11 +29,11 @@
 int              gck_data_openssl_parse_algo        (const gchar *name, int *mode);
 
 gboolean         gck_data_openssl_encrypt_block     (const gchar *dekinfo, const gchar *password, 
-                                                     const guchar *data, gsize n_data,
+                                                     gssize n_password, const guchar *data, gsize n_data,
                                                      guchar **encrypted, gsize *n_encrypted);
 
 GckDataResult    gck_data_openssl_decrypt_block     (const gchar *dekinfo, const gchar *password, 
-                                                     const guchar *data, gsize n_data, 
+                                                     gssize n_password, const guchar *data, gsize n_data, 
                                                      guchar **decrypted, gsize *n_decrypted);
 
 const gchar*     gck_data_openssl_get_dekinfo       (GHashTable *headers);

Modified: trunk/pkcs11/gck/gck-data-types.h
==============================================================================
--- trunk/pkcs11/gck/gck-data-types.h	(original)
+++ trunk/pkcs11/gck/gck-data-types.h	Mon Dec 22 23:31:40 2008
@@ -5,10 +5,13 @@
 
 typedef enum _GckDataResult {
 	GCK_DATA_FAILURE = -2,
+	GCK_DATA_LOCKED = -1, 
 	GCK_DATA_UNRECOGNIZED = 0,
 	GCK_DATA_SUCCESS = 1
 } GckDataResult;
 
 typedef void* (*GckDataAllocator) (void* p, unsigned long len);
 
+#define  GCK_DATA_ERROR      (g_quark_from_static_string ("gck-data-error"))
+
 #endif /* GCKDATA_H_ */

Modified: trunk/pkcs11/gck/gck-module.h
==============================================================================
--- trunk/pkcs11/gck/gck-module.h	(original)
+++ trunk/pkcs11/gck/gck-module.h	Mon Dec 22 23:31:40 2008
@@ -24,6 +24,10 @@
 
 #include <glib-object.h>
 
+#include "pkcs11/pkcs11.h"
+
+#include "gck-manager.h"
+
 typedef struct _GckSession GckSession;
 
 #define GCK_TYPE_MODULE               (gck_module_get_type ())

Modified: trunk/pkcs11/gck/gck-private-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-private-key.c	(original)
+++ trunk/pkcs11/gck/gck-private-key.c	Mon Dec 22 23:31:40 2008
@@ -280,13 +280,11 @@
 gck_private_key_store_private (GckPrivateKey *self, GckSexp *sexp, guint num_uses)
 {
 	g_return_if_fail (GCK_IS_PRIVATE_KEY (self));
-	g_return_if_fail (sexp);
-	g_return_if_fail (num_uses > 0);
 	
-	gck_sexp_ref (sexp);
+	if (sexp)
+		gck_sexp_ref (sexp);
 	if (self->pv->sexp) 
 		gck_sexp_unref (self->pv->sexp);
 	self->pv->sexp = sexp;
 	self->pv->sexp_uses = num_uses;
 }
-

Modified: trunk/pkcs11/gck/gck-util.c
==============================================================================
--- trunk/pkcs11/gck/gck-util.c	(original)
+++ trunk/pkcs11/gck/gck-util.c	Mon Dec 22 23:31:40 2008
@@ -67,6 +67,13 @@
 }
 
 CK_RV
+gck_util_set_string (CK_ATTRIBUTE_PTR attr, const gchar* string)
+{
+	g_return_val_if_fail (string, CKR_GENERAL_ERROR);
+	return gck_util_set_data (attr, string, strlen (string));
+}
+
+CK_RV
 gck_util_set_data (CK_ATTRIBUTE_PTR attr, CK_VOID_PTR value, CK_ULONG n_value)
 {
 	return gck_util_return_data (attr->pValue, &(attr->ulValueLen), value, n_value);

Modified: trunk/pkcs11/gck/gck-util.h
==============================================================================
--- trunk/pkcs11/gck/gck-util.h	(original)
+++ trunk/pkcs11/gck/gck-util.h	Mon Dec 22 23:31:40 2008
@@ -43,6 +43,9 @@
 CK_RV                 gck_util_set_ulong                          (CK_ATTRIBUTE_PTR attr, 
                                                                    CK_ULONG value);
 
+CK_RV                 gck_util_set_string                         (CK_ATTRIBUTE_PTR attr, 
+                                                                   const gchar* string);
+
 CK_RV                 gck_util_set_data                           (CK_ATTRIBUTE_PTR attr,
                                                                    CK_VOID_PTR value,
                                                                    CK_ULONG n_value);

Modified: trunk/pkcs11/gck/tests/unit-test-crypto.c
==============================================================================
--- trunk/pkcs11/gck/tests/unit-test-crypto.c	(original)
+++ trunk/pkcs11/gck/tests/unit-test-crypto.c	Mon Dec 22 23:31:40 2008
@@ -128,7 +128,7 @@
 		
 		ret = gck_crypto_symkey_generate_simple (all_generation_tests[i].cipher_algo, 
                                                          all_generation_tests[i].hash_algo,
-                                                         all_generation_tests[i].password,
+                                                         all_generation_tests[i].password, -1,
                                                          (guchar*)all_generation_tests[i].salt, 8,
                                                          all_generation_tests[i].iterations,
                                                          &key, NULL);
@@ -154,7 +154,7 @@
 		
 		ret = gck_crypto_symkey_generate_pkcs12 (all_generation_tests[i].cipher_algo, 
                                                          all_generation_tests[i].hash_algo,
-                                                         all_generation_tests[i].password,
+                                                         all_generation_tests[i].password, -1,
                                                          (guchar*)all_generation_tests[i].salt, 8,
                                                          all_generation_tests[i].iterations,
                                                          &key, NULL);
@@ -180,7 +180,7 @@
 		
 		ret = gck_crypto_symkey_generate_pbkdf2 (all_generation_tests[i].cipher_algo, 
                                                          all_generation_tests[i].hash_algo,
-                                                         all_generation_tests[i].password,
+                                                         all_generation_tests[i].password, -1,
                                                          (guchar*)all_generation_tests[i].salt, 8,
                                                          all_generation_tests[i].iterations,
                                                          &key, NULL);
@@ -206,7 +206,7 @@
 		
 		ret = gck_crypto_symkey_generate_pbe (all_generation_tests[i].cipher_algo, 
                                                       all_generation_tests[i].hash_algo,
-                                                      all_generation_tests[i].password,
+                                                      all_generation_tests[i].password, -1,
                                                       (guchar*)all_generation_tests[i].salt, 8,
                                                       all_generation_tests[i].iterations,
                                                       &key, NULL);

Modified: trunk/pkcs11/gck/tests/unit-test-data-openssl.c
==============================================================================
--- trunk/pkcs11/gck/tests/unit-test-data-openssl.c	(original)
+++ trunk/pkcs11/gck/tests/unit-test-data-openssl.c	Mon Dec 22 23:31:40 2008
@@ -80,7 +80,7 @@
 	dekinfo = gck_data_openssl_get_dekinfo (headers);
 	g_assert ("no dekinfo in headers" && dekinfo != NULL);
 	
-	res = gck_data_openssl_decrypt_block (dekinfo, "booo", data, n_data, &refdata, &n_refdata);
+	res = gck_data_openssl_decrypt_block (dekinfo, "booo", 4, data, n_data, &refdata, &n_refdata);
 	g_assert ("couldn't openssl decrypt block" && res == GCK_DATA_SUCCESS);
 	g_assert ("no data returned from openssl decrypt" && refdata != NULL);
 	g_assert ("invalid amount of data returned from openssl decrypt" && n_refdata == n_data);
@@ -110,7 +110,7 @@
 	dekinfo = gck_data_openssl_get_dekinfo (refheaders); 
 	g_assert ("no dekinfo in headers" && dekinfo != NULL);
 
-	ret = gck_data_openssl_encrypt_block (dekinfo, "booo", refdata, n_refdata, &encrypted, &n_encrypted);
+	ret = gck_data_openssl_encrypt_block (dekinfo, "booo", 4, refdata, n_refdata, &encrypted, &n_encrypted);
 	g_assert ("couldn't openssl encrypt block" && ret == TRUE);
 	g_assert ("no data returned from openssl encrypt" && encrypted != NULL);
 	g_assert ("invalid amount of data returned from openssl encrypt" && n_refdata <= n_encrypted);
@@ -134,12 +134,12 @@
 	
 	dekinfo = gck_data_openssl_prep_dekinfo (refheaders);
 	
-	ret = gck_data_openssl_encrypt_block (dekinfo, "password", TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted);
+	ret = gck_data_openssl_encrypt_block (dekinfo, "password", -1, TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted);
 	g_assert ("couldn't openssl encrypt block" && ret == TRUE);
 	g_assert ("no data returned from openssl encrypt" && encrypted != NULL);
 	g_assert ("invalid amount of data returned from openssl encrypt" && TEST_DATA_L <= n_encrypted);
 
-	res = gck_data_openssl_decrypt_block (dekinfo, "password", encrypted, n_encrypted, &decrypted, &n_decrypted);
+	res = gck_data_openssl_decrypt_block (dekinfo, "password", 8, encrypted, n_encrypted, &decrypted, &n_decrypted);
 	g_assert ("couldn't openssl decrypt block" && res == GCK_DATA_SUCCESS);
 	g_assert ("no data returned from openssl decrypt" && decrypted != NULL);
 

Modified: trunk/tests/gtest.make
==============================================================================
--- trunk/tests/gtest.make	(original)
+++ trunk/tests/gtest.make	Mon Dec 22 23:31:40 2008
@@ -20,9 +20,8 @@
 	$(GTHREAD_LIBS) 
 	
 noinst_PROGRAMS= \
-	run-auto-test \
-	run-prompt-test
-	
+	run-auto-test 
+		
 run-auto-test.c: $(UNIT_AUTO) Makefile.am $(top_srcdir)/tests/prep-gtest.sh
 	sh $(top_srcdir)/tests/prep-gtest.sh -b run-auto-test $(UNIT_AUTO)
 
@@ -37,25 +36,8 @@
 run_auto_test_CFLAGS = \
 	$(UNIT_FLAGS)
 
-run-prompt-test.c: $(UNIT_PROMPT) Makefile.am $(top_srcdir)/tests/prep-gtest.sh
-	sh $(top_srcdir)/tests/prep-gtest.sh -b run-prompt-test $(UNIT_PROMPT)
-
-run_prompt_test_SOURCES = \
-	run-prompt-test.c run-prompt-test.h \
-	$(UNIT_PROMPT)
-	
-run_prompt_test_LDADD = \
-	$(UNIT_LIBS) \
-	$(DAEMON_LIBS)
-
-run_prompt_test_CFLAGS = \
-	$(UNIT_FLAGS)
-
 # ------------------------------------------------------------------------------
 # Run the tests
 
 test-auto: $(noinst_PROGRAMS)
 	gtester -k -m=slow ./run-auto-test
-
-test-prompt: $(noinst_PROGRAMS)
-	gtester -k -m=slow ./run-prompt-test



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