gnome-keyring r1169 - in trunk: . common common/tests daemon keyrings keyrings/tests library pk pk/tests pkcs11 pkix pkix/tests po reference/tmpl ssh ssh/tests



Author: nnielsen
Date: Mon Jul  7 21:17:26 2008
New Revision: 1169
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1169&view=rev

Log:
	* common/gkr-crypto.c: Null terminate hex encodings properly
	
	* common/gkr-location.c: 
	* common/gkr-location.h: 
	* common/tests/unit-test-location.c: Add function to delete 
files, and 
	check if a location is a volume.
	
	* daemon/gkr-daemon-ops.c: Allow arbitrary item types.
	
	* keyrings/gkr-keyring.c:
	* keyrings/gkr-keyrings.c:
	* keyrings/gkr-keyrings.h: Can create keyrings in arbitrary 
locations.
	
	* daemon/gkr-daemon-ops.c:
	* keyrings/gkr-keyring.c: Consolidate the keyring unlocking 
logic.
	
	* keyrings/gkr-keyring-binary.c: 
	* keyrings/gkr-keyring-item.c:
	* keyrings/gkr-keyring-item.h: Functions to manage item 
attribute lists.
	
	* keyrings/gkr-keyring-item.c: 
	* keyrings/gkr-keyring-login.c:
	* keyrings/tests/unit-test-keyring-file.c: 
	* library/gnome-keyring.h:
	* pk/gkr-pk-cert.c:
	* pk/gkr-pk-index.c:
	* pk/gkr-pk-index.h:
	* pk/gkr-pk-object.c:
	* pk/gkr-pk-object.h:
	* pk/gkr-pk-object-manager.c:
	* pk/gkr-pk-privkey.c:
	* pk/gkr-pk-pubkey.c:
	* pk/gkr-pk-root-storage.c: (added)
	* pk/gkr-pk-root-storage.h: (added)
	* pk/gkr-pk-session-storage.c: (added)
	* pk/gkr-pk-session-storage.h: (added)
	* pk/gkr-pk-storage.c: (added)
	* pk/gkr-pk-storage.h: (added)
	* pk/Makefile.am:
	* pk/tests/unit-test-pk-cert.c:
	* pk/tests/unit-test-pk-index.c:
	* pk/tests/unit-test-pk-netscape-trust.c:
	* pkcs11/gkr-pkcs11-daemon-session.c: 
	* pkix/gkr-pkix-marshal.list
	* pkix/gkr-pkix-parser.c:
	* pkix/gkr-pkix-parser.h:
	* pkix/tests/unit-test-pkix-parser.c:
	* pkix/tests/unit-test-pkix-serialize.c:
	* configure.in: Put indexes into keyrings, and rework how 
storage
	of PK objects is thought out. 

	* daemon/gkr-daemon.c:   
	* pkix/gkr-pkix-openssl.c:
	* pkix/gkr-pkix-openssl.h:
	* pkix/gkr-pkix-pem.c:
	* pkix/gkr-pkix-pem.h:
	* pkix/tests/unit-test-pkix-openssl.c: (added)
	* ssh/gkr-ssh-daemon-io.c:
	* ssh/gkr-ssh-daemon-ops.c:
	* ssh/gkr-ssh-proto.c:
	* ssh/gkr-ssh-storage.c: (added)
	* ssh/gkr-ssh-storage.h: (added)
	* ssh/Makefile.am: 
	* ssh/tests/Makefile.am: (added)
	* ssh/tests/unit-test-ssh-storage.c: (added) 
	Add an SSH key store which loads ~/.ssh



Added:
   trunk/pk/gkr-pk-root-storage.c
   trunk/pk/gkr-pk-root-storage.h
   trunk/pk/gkr-pk-session-storage.c
   trunk/pk/gkr-pk-session-storage.h
   trunk/pk/gkr-pk-storage.c
   trunk/pk/gkr-pk-storage.h
   trunk/pkix/tests/unit-test-pkix-openssl.c
   trunk/ssh/gkr-ssh-storage.c
   trunk/ssh/gkr-ssh-storage.h
   trunk/ssh/tests/   (props changed)
   trunk/ssh/tests/Makefile.am
   trunk/ssh/tests/unit-test-ssh-storage.c
Modified:
   trunk/ChangeLog
   trunk/common/gkr-crypto.c
   trunk/common/gkr-location.c
   trunk/common/gkr-location.h
   trunk/common/tests/unit-test-location.c
   trunk/configure.in
   trunk/daemon/gkr-daemon-ops.c
   trunk/daemon/gkr-daemon.c
   trunk/keyrings/gkr-keyring-binary.c
   trunk/keyrings/gkr-keyring-item.c
   trunk/keyrings/gkr-keyring-item.h
   trunk/keyrings/gkr-keyring-login.c
   trunk/keyrings/gkr-keyring.c
   trunk/keyrings/gkr-keyring.h
   trunk/keyrings/gkr-keyrings.c
   trunk/keyrings/gkr-keyrings.h
   trunk/keyrings/tests/unit-test-keyring-file.c
   trunk/library/gnome-keyring.h
   trunk/pk/Makefile.am
   trunk/pk/gkr-pk-cert.c
   trunk/pk/gkr-pk-index.c
   trunk/pk/gkr-pk-index.h
   trunk/pk/gkr-pk-object-manager.c
   trunk/pk/gkr-pk-object-storage.c
   trunk/pk/gkr-pk-object-storage.h
   trunk/pk/gkr-pk-object.c
   trunk/pk/gkr-pk-object.h
   trunk/pk/gkr-pk-privkey.c
   trunk/pk/gkr-pk-pubkey.c
   trunk/pk/tests/unit-test-pk-cert.c
   trunk/pk/tests/unit-test-pk-index.c
   trunk/pk/tests/unit-test-pk-netscape-trust.c
   trunk/pkcs11/gkr-pkcs11-daemon-session.c
   trunk/pkix/gkr-pkix-marshal.list
   trunk/pkix/gkr-pkix-openssl.c
   trunk/pkix/gkr-pkix-openssl.h
   trunk/pkix/gkr-pkix-parser.c
   trunk/pkix/gkr-pkix-parser.h
   trunk/pkix/gkr-pkix-pem.c
   trunk/pkix/gkr-pkix-pem.h
   trunk/pkix/tests/Makefile.am
   trunk/pkix/tests/unit-test-pkix-parser.c
   trunk/pkix/tests/unit-test-pkix-serialize.c
   trunk/po/ChangeLog
   trunk/po/POTFILES.in
   trunk/reference/tmpl/gnome-keyring-item-info.sgml
   trunk/ssh/Makefile.am
   trunk/ssh/gkr-ssh-daemon-io.c
   trunk/ssh/gkr-ssh-daemon-ops.c
   trunk/ssh/gkr-ssh-proto.c

Modified: trunk/common/gkr-crypto.c
==============================================================================
--- trunk/common/gkr-crypto.c	(original)
+++ trunk/common/gkr-crypto.c	Mon Jul  7 21:17:26 2008
@@ -82,7 +82,7 @@
 	gcrypt_initialized = TRUE;
 }
 
-static const char HEXC[] = "0123456789abcdef";
+static const char HEXC[] = "0123456789ABCDEF";
 
 gboolean
 gkr_crypto_hex_encode (const guchar *data, gsize n_data, 
@@ -101,7 +101,9 @@
     
 		n_data--;
 	}
-	
+
+	/* Null terminate */
+	*encoded = 0;
 	return TRUE;
 }
 
@@ -125,7 +127,7 @@
     		if (!isspace (*data)) {
     			
 	        	/* Find the position */
-			pos = strchr (HEXC, tolower (*data));
+			pos = strchr (HEXC, toupper (*data));
 			if (pos == 0)
 				break;
 

Modified: trunk/common/gkr-location.c
==============================================================================
--- trunk/common/gkr-location.c	(original)
+++ trunk/common/gkr-location.c	Mon Jul  7 21:17:26 2008
@@ -35,7 +35,9 @@
 
 #include <glib.h>
 #include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
 
+#include <errno.h>
 #include <string.h>
 
 #define LOC_DELIMITER   ":"
@@ -1017,6 +1019,27 @@
 }
 
 gboolean
+gkr_location_is_volume (GQuark loc)
+{
+	const gchar *sloc;
+	const gchar *delim;
+	
+	if (!loc)
+		return FALSE;
+	
+	sloc = g_quark_to_string (loc);
+	g_return_val_if_fail (sloc, FALSE);
+
+	delim = strchr (sloc, LOC_DELIMITER_C);
+	if (!delim) {
+		g_warning ("The '%s' location is invalid", sloc);
+		return FALSE;
+	}
+	
+	return (delim[1] == 0);
+}
+
+gboolean
 gkr_location_is_descendant (GQuark parent, GQuark descendant)
 {
 	const gchar *sparent = g_quark_to_string (parent);
@@ -1103,3 +1126,32 @@
 	
 	return ret;
 }
+
+gboolean
+gkr_location_delete_file (GQuark loc, GError **err)
+{
+	gchar *path;
+	int eno;
+	
+	g_return_val_if_fail (loc != 0, FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+
+	/* Should be successful when file doesn't exist */
+	path = gkr_location_to_path (loc);
+	if (!path)
+		return TRUE;
+
+	if (g_unlink (path) < 0) {
+		eno = errno;
+		
+		/* Should be successful when file doesn't exist */
+		if (eno != ENOENT) {
+			g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (eno), 
+			             _("Couldn't delete the file: %s"), g_strerror (eno));
+			return FALSE;
+		}
+	}
+	
+	g_free (path);
+	return TRUE;	
+}

Modified: trunk/common/gkr-location.h
==============================================================================
--- trunk/common/gkr-location.h	(original)
+++ trunk/common/gkr-location.h	Mon Jul  7 21:17:26 2008
@@ -57,6 +57,8 @@
  
 gchar*         gkr_location_to_path        (GQuark loc);
 
+gboolean       gkr_location_is_volume      (GQuark loc);
+
 gboolean       gkr_location_is_descendant  (GQuark parent, GQuark descendant);
 
 GQuark         gkr_location_get_volume     (GQuark loc);
@@ -73,6 +75,8 @@
 
 gboolean       gkr_location_write_file     (GQuark loc, const guchar *data, gssize len, GError **err);
 
+gboolean       gkr_location_delete_file    (GQuark loc, GError **err);
+
 /* -------------------------------------------------------------------------- */
 
 #define GKR_TYPE_LOCATION_MANAGER             (gkr_location_manager_get_type ())

Modified: trunk/common/tests/unit-test-location.c
==============================================================================
--- trunk/common/tests/unit-test-location.c	(original)
+++ trunk/common/tests/unit-test-location.c	Mon Jul  7 21:17:26 2008
@@ -72,6 +72,10 @@
 
 	path2 = gkr_location_to_path (child);
 	CuAssert (cu, "should return non-null path", path2 != NULL);
+	
+	CuAssert (cu, "should be volume", gkr_location_is_volume (GKR_LOCATION_VOLUME_HOME));
+	CuAssert (cu, "should not be volume", !gkr_location_is_volume (loc));
+	CuAssert (cu, "should not be volume", !gkr_location_is_volume (child));
 }
 
 void unit_test_location_trailing (CuTest* cu)
@@ -142,3 +146,32 @@
 	
 }
 
+void unit_test_location_fileops (CuTest* cu)
+{
+	const guchar *data = (guchar*)"TEST DATA FOR FILE";
+	guchar *result;
+	gsize n_result, len;
+	gboolean ret;
+	GQuark loc;
+	
+	loc = gkr_location_from_child (GKR_LOCATION_VOLUME_FILE, "/tmp/gkr-test-location-fileops");
+	CuAssert (cu, "should return a non-zero quark", loc != 0);
+	
+	len = strlen ((gchar*)data);
+	ret = gkr_location_write_file (loc, data, len, NULL);
+	CuAssert (cu, "should be successful writing to temp file", ret == TRUE);
+
+	ret = gkr_location_read_file (loc, &result, &n_result, NULL);
+	CuAssert (cu, "should be successful reading from temp file", ret == TRUE);
+	CuAssert (cu, "should have read same length as written", n_result == len);
+	CuAssert (cu, "should have read same data as written", memcmp (data, result, len) == 0);
+	
+	ret = gkr_location_delete_file (loc, NULL);
+	CuAssert (cu, "should have successfully deleted file", ret == TRUE);
+
+	ret = gkr_location_read_file (loc, &result, &n_result, NULL);
+	CuAssert (cu, "shouldn't be able to read from deleted file", ret == FALSE);
+
+	ret = gkr_location_delete_file (loc, NULL);
+	CuAssert (cu, "should be able to successfully delete non-existant file", ret == TRUE);
+}

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Jul  7 21:17:26 2008
@@ -362,6 +362,8 @@
 	root_status="$with_root_certs"
 fi
 
+AM_CONDITIONAL(WITH_ROOT_CERTS, test -n "$with_root_certs")
+
 
 # --------------------------------------------------------------------
 # Check for /dev/random
@@ -477,6 +479,7 @@
 po/Makefile.in
 reference/Makefile
 ssh/Makefile
+ssh/tests/Makefile
 tests/Makefile
 ui/Makefile
 library/gnome-keyring-1.pc

Modified: trunk/daemon/gkr-daemon-ops.c
==============================================================================
--- trunk/daemon/gkr-daemon-ops.c	(original)
+++ trunk/daemon/gkr-daemon-ops.c	Mon Jul  7 21:17:26 2008
@@ -286,72 +286,6 @@
 	return ret;
 }
 
-static gboolean 
-check_keyring_ask_request (GkrAskRequest* ask)
-{
-	GkrKeyring *keyring;
-	const gchar *password;
-	gchar *display;
-	
-	keyring = GKR_KEYRING (gkr_ask_request_get_object (ask));
-	g_assert (GKR_IS_KEYRING (keyring));
-
-	if (!keyring->locked) {
-		ask->response = GKR_ASK_RESPONSE_ALLOW;
-		return GKR_ASK_STOP_REQUEST;
-	}
-	
-	/* If they typed a password, try it out */
-	if (ask->response >= GKR_ASK_RESPONSE_ALLOW) {
-		
-		g_assert (ask->typed_password);
-		if (!gkr_keyring_unlock (keyring, ask->typed_password)) {
-			/* Bad password, try again */
-			ask->response = GKR_ASK_RESPONSE_NONE;
-			return GKR_ASK_CONTINUE_REQUEST;
-		}
-		
-		/* Did they ask us to remember the password? */
-		if (ask->checked) {
-			display = g_strdup_printf (_("Unlock password for %s keyring"), 
-			                           keyring->keyring_name);
-			gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
-			                                 display, ask->typed_password, 
-			                                 "keyring", gkr_location_to_string (keyring->location), NULL);
-			g_free (display);
-		}
-	}
-	
-	/* 
-	 * We can automatically unlock keyrings that have their password
-	 * stored in the 'login' keyring.
-	 */
-	password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
-	                                            "keyring", gkr_location_to_string (keyring->location), NULL);
-	if (password) {
-		if (gkr_keyring_unlock (keyring, password)) {
-			
-			/* A good password, unlocked, all done */
-			ask->response = GKR_ASK_RESPONSE_ALLOW;
-			return GKR_ASK_STOP_REQUEST;
-			
-		} else {
-			
-			/* A bad internal password */
-			gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
-			                                 "keyring", gkr_location_to_string (keyring->location), NULL);
-		}
-	}	
-
-	/* If the keyring is unlocked then no need to continue */
-	if (!keyring->locked) {
-		ask->response = GKR_ASK_RESPONSE_ALLOW;
-		return GKR_ASK_STOP_REQUEST;
-	}
-	
-	return GKR_ASK_DONT_CARE;
-}
-
 static gboolean
 request_keyring_access (GkrKeyringRequest *req, GkrKeyring *keyring)
 {
@@ -433,7 +367,7 @@
 		gkr_ask_request_set_check_option (ask, _("Automatically unlock this keyring when I log in."));
 	
 	/* Intercept item access requests to see if we still need to prompt */
-	g_signal_connect (ask, "check-request", G_CALLBACK (check_keyring_ask_request), NULL);
+	g_signal_connect (ask, "check-request", G_CALLBACK (gkr_keyring_ask_check_unlock), NULL);
 	
 	g_free (primary);
 	g_free (message);
@@ -1196,8 +1130,7 @@
 		return FALSE;
 	}
 
-	if ((type & GNOME_KEYRING_ITEM_TYPE_MASK) >= GNOME_KEYRING_ITEM_LAST_TYPE ||
-	    display_name == NULL || secret == NULL) {
+	if (display_name == NULL || secret == NULL) {
 		res = GNOME_KEYRING_RESULT_BAD_ARGUMENTS;
 		goto out;
 	}
@@ -1227,7 +1160,7 @@
 	}
 	
 	if (update_if_exists) {
-		item = gkr_keyring_find_item (keyring, type, keyring->locked ? hashed : attributes);
+		item = gkr_keyring_find_item (keyring, type, keyring->locked ? hashed : attributes, TRUE);
 		if (item) {
 			/* Make sure we have access to the previous item */
 			if (!request_item_access (req, item, GNOME_KEYRING_ACCESS_WRITE, TRUE))
@@ -1691,7 +1624,7 @@
 
 	/* Need at least one attribute to match on */
 	if (ctx.attributes->len > 0) {
-		ctx.hashed = gkr_keyring_item_attributes_hash (ctx.attributes);
+		ctx.hashed = gkr_attribute_list_hash (ctx.attributes);
 		ctx.nfound = 0;
 		ctx.req = req;
 		ctx.items = NULL;

Modified: trunk/daemon/gkr-daemon.c
==============================================================================
--- trunk/daemon/gkr-daemon.c	(original)
+++ trunk/daemon/gkr-daemon.c	Mon Jul  7 21:17:26 2008
@@ -39,6 +39,7 @@
 
 #ifdef WITH_SSH
 #include "ssh/gkr-ssh-daemon.h"
+#include "ssh/gkr-ssh-storage.h"
 #endif
 
 #include "ui/gkr-ask-daemon.h"
@@ -460,7 +461,8 @@
 
 #ifdef WITH_SSH	
 	if (check_run_component ("ssh")) {
-		if (!gkr_daemon_ssh_io_initialize ())
+		if (!gkr_daemon_ssh_io_initialize () ||
+		    !gkr_ssh_storage_initialize ())
 			cleanup_and_exit (1);
 	}
 #endif

Modified: trunk/keyrings/gkr-keyring-binary.c
==============================================================================
--- trunk/keyrings/gkr-keyring-binary.c	(original)
+++ trunk/keyrings/gkr-keyring-binary.c	Mon Jul  7 21:17:26 2008
@@ -341,7 +341,7 @@
 		gkr_buffer_add_uint32 (buffer, item->id);
 		gkr_buffer_add_uint32 (buffer, item->type);
 		
-		hashed = gkr_keyring_item_attributes_hash (item->attributes);
+		hashed = gkr_attribute_list_hash (item->attributes);
 
 		if (!gkr_proto_add_attribute_list (buffer, hashed)) {
 			gnome_keyring_attribute_list_free (hashed);

Modified: trunk/keyrings/gkr-keyring-item.c
==============================================================================
--- trunk/keyrings/gkr-keyring-item.c	(original)
+++ trunk/keyrings/gkr-keyring-item.c	Mon Jul  7 21:17:26 2008
@@ -169,6 +169,7 @@
 	item->keyring = keyring;
 	item->id = id;
 	item->type = type;
+	item->attributes = gnome_keyring_attribute_list_new ();
 	
 	/* Make sure we get disconnected when keyring goes away */
 	g_object_add_weak_pointer (G_OBJECT (item->keyring), (gpointer*)&(item->keyring));
@@ -195,6 +196,34 @@
 	return item;
 }
 
+GkrKeyringItem*
+gkr_keyring_item_clone (GkrKeyring* new_keyring, GkrKeyringItem *item)
+{
+	GkrKeyringItem *nitem = g_object_new (GKR_TYPE_KEYRING_ITEM, NULL);
+
+	g_return_val_if_fail (GKR_IS_KEYRING (new_keyring), NULL);
+	g_return_val_if_fail (GKR_IS_KEYRING_ITEM (item), NULL);
+		
+	nitem->keyring = new_keyring;
+	nitem->id = item->id;
+	nitem->locked = item->locked;
+
+	nitem->type = item->type;
+	nitem->secret = gkr_secure_strdup (item->secret);
+	nitem->display_name = g_strdup (item->display_name);
+
+	nitem->attributes = gnome_keyring_attribute_list_copy (item->attributes);
+	nitem->acl = gnome_keyring_acl_copy (item->acl);
+	
+	nitem->ctime = item->ctime;
+	nitem->mtime = item->mtime;
+	
+	/* Make sure we get disconnected when keyring goes away */
+	g_object_add_weak_pointer (G_OBJECT (item->keyring), (gpointer*)&(item->keyring));
+		
+	return item;
+}
+
 gboolean
 gkr_keyring_item_match (GkrKeyringItem *item, GnomeKeyringItemType type, 
                         GnomeKeyringAttributeList *attributes, gboolean match_all)
@@ -254,8 +283,94 @@
 	return TRUE;
 }
 
+/* -----------------------------------------------------------------------------
+ * ATTRIBUTE LIST FUNCTIONS
+ */
+
+void
+gkr_attribute_list_set (GnomeKeyringAttributeList *attrs, GnomeKeyringAttribute *attr)
+{
+	GnomeKeyringAttribute *set;
+	GnomeKeyringAttribute last;
+	gchar *tofree = NULL;
+	
+	g_return_if_fail (attrs);
+	g_return_if_fail (attr);
+	g_return_if_fail (attr->name);
+	
+	set = gkr_attribute_list_find (attrs, attr->name);
+	
+	/* Found, appropriate for our own uses */
+	if (set) {
+		if (set->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
+			tofree = set->value.string;
+			set->value.string = NULL;
+		}
+		
+	/* Not found, add a new one to the end */
+	} else {
+		memset (&last, 0, sizeof (last));
+		g_array_append_val (attrs, last);
+		set = &g_array_index (attrs, GnomeKeyringAttribute, attrs->len - 1);
+		set->name = g_strdup (attr->name);
+	}
+	
+	/* Set the actual value */
+	set->type = attr->type;
+	switch (attr->type) {
+	case GNOME_KEYRING_ATTRIBUTE_TYPE_STRING:
+		set->value.string = g_strdup (attr->value.string);
+		break;
+	case GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32:
+		set->value.integer = attr->value.integer;
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+	
+	g_free (tofree);
+}
+
+GnomeKeyringAttribute*
+gkr_attribute_list_find (GnomeKeyringAttributeList *attrs, const gchar *name)
+{
+	GnomeKeyringAttribute *attr;
+	int i;
+	
+	g_return_val_if_fail (attrs, NULL);
+	g_return_val_if_fail (name, NULL);
+	
+	for (i = 0; i < attrs->len; i++) {
+		attr = &gnome_keyring_attribute_list_index (attrs, i);
+		g_return_val_if_fail (attr->name, NULL);
+		if (strcmp (attr->name, name) == 0)
+			return attr;
+	}
+
+	return NULL;
+}
+
+void
+gkr_attribute_list_delete (GnomeKeyringAttributeList *attrs, const gchar *name)
+{
+	GnomeKeyringAttribute *attr;
+	int i;
+	
+	g_return_if_fail (attrs);
+	g_return_if_fail (name);
+	
+	for (i = 0; i < attrs->len; i++) {
+		attr = &gnome_keyring_attribute_list_index (attrs, i);
+		g_return_if_fail (attr->name);
+		if (strcmp (attr->name, name) == 0) {
+			g_array_remove_index_fast (attrs, i);
+			return;
+		}
+	}
+}
+
 GnomeKeyringAttributeList *
-gkr_keyring_item_attributes_hash (GnomeKeyringAttributeList *attributes)
+gkr_attribute_list_hash (GnomeKeyringAttributeList *attributes)
 {
 	GnomeKeyringAttributeList *hashed;
 	GnomeKeyringAttribute *orig_attribute;

Modified: trunk/keyrings/gkr-keyring-item.h
==============================================================================
--- trunk/keyrings/gkr-keyring-item.h	(original)
+++ trunk/keyrings/gkr-keyring-item.h	Mon Jul  7 21:17:26 2008
@@ -83,13 +83,24 @@
 GkrKeyringItem*    gkr_keyring_item_create      (GkrKeyring* keyring, 
                                                  GnomeKeyringItemType type);
 
+GkrKeyringItem*    gkr_keyring_item_clone       (GkrKeyring* new_keyring, 
+                                                 GkrKeyringItem *item);
+
 gboolean           gkr_keyring_item_match       (GkrKeyringItem *item, 
                                                  GnomeKeyringItemType type, 
                                                  GnomeKeyringAttributeList *attributes, 
                                                  gboolean match_all);
 
+void                        gkr_attribute_list_set     (GnomeKeyringAttributeList *attrs, 
+                                                        GnomeKeyringAttribute *attr);
+
+GnomeKeyringAttribute*      gkr_attribute_list_find    (GnomeKeyringAttributeList *attrs,
+                                                        const gchar *name);
+
+void                        gkr_attribute_list_delete  (GnomeKeyringAttributeList *attrs,
+                                                        const gchar *name);
 
-GnomeKeyringAttributeList*  gkr_keyring_item_attributes_hash (GnomeKeyringAttributeList *attributes);
+GnomeKeyringAttributeList*  gkr_attribute_list_hash    (GnomeKeyringAttributeList *attrs);
                                                  
 G_END_DECLS
 

Modified: trunk/keyrings/gkr-keyring-login.c
==============================================================================
--- trunk/keyrings/gkr-keyring-login.c	(original)
+++ trunk/keyrings/gkr-keyring-login.c	Mon Jul  7 21:17:26 2008
@@ -232,7 +232,7 @@
 	attrs = string_attribute_list_va (args);
 	va_end (args);
 	
-	item = gkr_keyring_find_item (login, type, attrs);
+	item = gkr_keyring_find_item (login, type, attrs, TRUE);
 	
 	if (!item) {
 		item = gkr_keyring_item_create (login, type);
@@ -270,7 +270,7 @@
 	attrs = string_attribute_list_va (args);
 	va_end (args);
 				
-	item = gkr_keyring_find_item (login, type, attrs);
+	item = gkr_keyring_find_item (login, type, attrs, TRUE);
 	gnome_keyring_attribute_list_free (attrs);
 	
 	if (item)
@@ -298,7 +298,7 @@
 	attrs = string_attribute_list_va (args);
 	va_end (args);
 		
-	item = gkr_keyring_find_item (login, type, attrs);
+	item = gkr_keyring_find_item (login, type, attrs, TRUE);
 	gnome_keyring_attribute_list_free (attrs);
 	
 	if (item) {

Modified: trunk/keyrings/gkr-keyring.c
==============================================================================
--- trunk/keyrings/gkr-keyring.c	(original)
+++ trunk/keyrings/gkr-keyring.c	Mon Jul  7 21:17:26 2008
@@ -25,8 +25,9 @@
 #include "config.h"
 
 #include "gkr-keyring.h"
-#include "gkr-keyrings.h"
 #include "gkr-keyring-item.h"
+#include "gkr-keyring-login.h"
+#include "gkr-keyrings.h"
 
 #include "common/gkr-buffer.h"
 #include "common/gkr-location.h"
@@ -36,6 +37,7 @@
 #include "library/gnome-keyring-proto.h"
 
 #include <glib.h>
+#include <glib/gi18n.h>
 
 #include <gcrypt.h>
 
@@ -248,16 +250,18 @@
 }
 
 GkrKeyring*
-gkr_keyring_create (GQuark volume, const gchar *keyring_name, const gchar *password)
+gkr_keyring_create (GQuark location, const gchar *keyring_name, const gchar *password)
 {
 	GkrKeyring *keyring;
 	
-	if (!volume)
-		volume = GKR_LOCATION_VOLUME_LOCAL;
+	if (!location)
+		location = GKR_LOCATION_VOLUME_LOCAL;
+	if (gkr_location_is_volume (location))
+		location = get_default_location_for_name (location, keyring_name);
 	
 	keyring = gkr_keyring_new (keyring_name, 0);
 	if (keyring != NULL) {
-		keyring->location = get_default_location_for_name (volume, keyring_name);
+		keyring->location = location;
 		keyring->locked = FALSE;
 		keyring->password = gkr_secure_strdup (password);
 		keyring->salt_valid = FALSE;
@@ -306,14 +310,14 @@
 
 GkrKeyringItem*  
 gkr_keyring_find_item (GkrKeyring *keyring, GnomeKeyringItemType type, 
-                       GnomeKeyringAttributeList *attrs)
+                       GnomeKeyringAttributeList *attrs, gboolean match_all)
 {    
 	GkrKeyringItem *item;
 	GList *l;
 	
 	for (l = keyring->items; l; l = g_list_next (l)) {
 		item = GKR_KEYRING_ITEM (l->data);
-		if (gkr_keyring_item_match (item, type, attrs, TRUE))
+		if (gkr_keyring_item_match (item, type, attrs, match_all))
 			return item;
 	}
 	
@@ -549,3 +553,69 @@
 		
 	return FALSE;
 }
+
+gboolean 
+gkr_keyring_ask_check_unlock (GkrAskRequest* ask)
+{
+	GkrKeyring *keyring;
+	const gchar *password;
+	gchar *display;
+	
+	keyring = GKR_KEYRING (gkr_ask_request_get_object (ask));
+	g_assert (GKR_IS_KEYRING (keyring));
+
+	if (!keyring->locked) {
+		ask->response = GKR_ASK_RESPONSE_ALLOW;
+		return GKR_ASK_STOP_REQUEST;
+	}
+	
+	/* If they typed a password, try it out */
+	if (ask->response >= GKR_ASK_RESPONSE_ALLOW) {
+		
+		g_assert (ask->typed_password);
+		if (!gkr_keyring_unlock (keyring, ask->typed_password)) {
+			/* Bad password, try again */
+			ask->response = GKR_ASK_RESPONSE_NONE;
+			return GKR_ASK_CONTINUE_REQUEST;
+		}
+		
+		/* Did they ask us to remember the password? */
+		if (ask->checked) {
+			display = g_strdup_printf (_("Unlock password for %s keyring"), 
+			                           keyring->keyring_name);
+			gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
+			                                 display, ask->typed_password, 
+			                                 "keyring", gkr_location_to_string (keyring->location), NULL);
+			g_free (display);
+		}
+	}
+	
+	/* 
+	 * We can automatically unlock keyrings that have their password
+	 * stored in the 'login' keyring.
+	 */
+	password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
+	                                            "keyring", gkr_location_to_string (keyring->location), NULL);
+	if (password) {
+		if (gkr_keyring_unlock (keyring, password)) {
+			
+			/* A good password, unlocked, all done */
+			ask->response = GKR_ASK_RESPONSE_ALLOW;
+			return GKR_ASK_STOP_REQUEST;
+			
+		} else {
+			
+			/* A bad internal password */
+			gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
+			                                 "keyring", gkr_location_to_string (keyring->location), NULL);
+		}
+	}	
+
+	/* If the keyring is unlocked then no need to continue */
+	if (!keyring->locked) {
+		ask->response = GKR_ASK_RESPONSE_ALLOW;
+		return GKR_ASK_STOP_REQUEST;
+	}
+	
+	return GKR_ASK_DONT_CARE;
+}

Modified: trunk/keyrings/gkr-keyring.h
==============================================================================
--- trunk/keyrings/gkr-keyring.h	(original)
+++ trunk/keyrings/gkr-keyring.h	Mon Jul  7 21:17:26 2008
@@ -37,6 +37,8 @@
 
 #include "library/gnome-keyring.h"
 
+#include "ui/gkr-ask-request.h"
+
 G_BEGIN_DECLS
 
 #define GKR_TYPE_KEYRING             (gkr_keyring_get_type())
@@ -95,7 +97,7 @@
 GkrKeyringItem*  gkr_keyring_get_item           (GkrKeyring *keyring, guint id);
 
 GkrKeyringItem*  gkr_keyring_find_item          (GkrKeyring *keyring, GnomeKeyringItemType type, 
-                                                 GnomeKeyringAttributeList *attrs);
+                                                 GnomeKeyringAttributeList *attrs, gboolean match_all);
 
 void             gkr_keyring_add_item           (GkrKeyring* keyring, GkrKeyringItem* item);
 
@@ -117,6 +119,9 @@
 
 gboolean         gkr_keyring_is_insecure        (GkrKeyring *keyring);
 
+/* Used with the check-request signal on GkrAskRequest to unlock a keyring */
+gboolean         gkr_keyring_ask_check_unlock   (GkrAskRequest* ask);
+
 /* -----------------------------------------------------------------------------
  * FILE FORMATS
  * 

Modified: trunk/keyrings/gkr-keyrings.c
==============================================================================
--- trunk/keyrings/gkr-keyrings.c	(original)
+++ trunk/keyrings/gkr-keyrings.c	Mon Jul  7 21:17:26 2008
@@ -338,6 +338,34 @@
 	return NULL;
 }
 
+GkrKeyring*
+gkr_keyrings_for_location (GQuark location)
+{
+	GkrKeyring *keyring;
+	GList *l;
+	
+	keyrings_init ();
+
+	for (l = keyrings; l != NULL; l = l->next) {
+		keyring = GKR_KEYRING (l->data);
+		if (keyring->location == location)
+			return keyring;
+	}
+
+	/* Try and load the keyring */
+	if (gkr_location_test_file (location, G_FILE_TEST_IS_REGULAR)) {
+		keyring = gkr_keyring_new ("", location);
+		if (gkr_keyring_update_from_disk (keyring))
+			gkr_keyrings_add (keyring);
+		else
+			keyring = NULL;
+		g_object_unref (keyring);
+		return keyring;
+	}
+
+	return NULL;
+}
+
 gboolean 
 gkr_keyrings_foreach (GkrKeyringEnumFunc func, gpointer data)
 {

Modified: trunk/keyrings/gkr-keyrings.h
==============================================================================
--- trunk/keyrings/gkr-keyrings.h	(original)
+++ trunk/keyrings/gkr-keyrings.h	Mon Jul  7 21:17:26 2008
@@ -40,6 +40,8 @@
 
 GkrKeyring*     gkr_keyrings_find          (const gchar *name);
 
+GkrKeyring*     gkr_keyrings_for_location  (GQuark location);
+
 GkrKeyring*     gkr_keyrings_get_session   (void);
 
 guint           gkr_keyrings_get_count     (void);

Modified: trunk/keyrings/tests/unit-test-keyring-file.c
==============================================================================
--- trunk/keyrings/tests/unit-test-keyring-file.c	(original)
+++ trunk/keyrings/tests/unit-test-keyring-file.c	Mon Jul  7 21:17:26 2008
@@ -87,7 +87,7 @@
 	gnome_keyring_attribute_list_append_string (attrs, "bird", "cheep");
 	gnome_keyring_attribute_list_append_string (attrs, "iguana", "");
 	gnome_keyring_attribute_list_append_uint32 (attrs, "num", 3); 
-	item = gkr_keyring_find_item (keyring, GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs);
+	item = gkr_keyring_find_item (keyring, GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs, TRUE);
 	gnome_keyring_attribute_list_free (attrs);
 	CuAssert (cu, "Couldn't find item #3", item != NULL);
 	CuAssert (cu, "Invalid item found", item->id == 3);

Modified: trunk/library/gnome-keyring.h
==============================================================================
--- trunk/library/gnome-keyring.h	(original)
+++ trunk/library/gnome-keyring.h	Mon Jul  7 21:17:26 2008
@@ -41,7 +41,9 @@
 	GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
 	GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD,
 	
-	/*< private >*/
+	GNOME_KEYRING_ITEM_PK_STORAGE = 0x100,
+	
+	/* Not used, remains here only for compatibility */
 	GNOME_KEYRING_ITEM_LAST_TYPE,
 
 } GnomeKeyringItemType;

Modified: trunk/pk/Makefile.am
==============================================================================
--- trunk/pk/Makefile.am	(original)
+++ trunk/pk/Makefile.am	Mon Jul  7 21:17:26 2008
@@ -1,3 +1,10 @@
+
+if WITH_ROOT_CERTS
+ROOT_SRCS = gkr-pk-root-storage.c gkr-pk-root-storage.h
+else
+ROOT_SRCS = 
+endif
+
 noinst_LTLIBRARIES=libgkr-pk.la
 
 INCLUDES=	\
@@ -17,11 +24,13 @@
 	gkr-pk-netscape-trust.c gkr-pk-netscape-trust.h \
 	gkr-pk-object.c gkr-pk-object.h \
 	gkr-pk-object-manager.c gkr-pk-object-manager.h \
-	gkr-pk-object-storage.c gkr-pk-object-storage.h \
 	gkr-pk-places.h \
 	gkr-pk-privkey.c gkr-pk-privkey.h \
 	gkr-pk-pubkey.c gkr-pk-pubkey.h \
-	gkr-pk-util.c gkr-pk-util.h
+	gkr-pk-session-storage.c gkr-pk-session-storage.h \
+	gkr-pk-storage.c gkr-pk-storage.h \
+	gkr-pk-util.c gkr-pk-util.h \
+	$(ROOT_SRCS)
 
 libgkr_pk_la_LIBADD = \
 	$(top_builddir)/ui/libgkr-ui.la \

Modified: trunk/pk/gkr-pk-cert.c
==============================================================================
--- trunk/pk/gkr-pk-cert.c	(original)
+++ trunk/pk/gkr-pk-cert.c	Mon Jul  7 21:17:26 2008
@@ -28,9 +28,9 @@
 #include "gkr-pk-netscape-trust.h"
 #include "gkr-pk-object.h"
 #include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
 #include "gkr-pk-privkey.h"
 #include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
 #include "gkr-pk-util.h"
 
 #include "common/gkr-crypto.h"
@@ -125,7 +125,7 @@
 	obj = GKR_PK_OBJECT (cert);
 	
 	g_return_val_if_fail (obj->storage, CKR_GENERAL_ERROR);	
-	if (!gkr_pk_object_storage_load_complete (obj->storage, obj, &err)) {
+	if (!gkr_pk_storage_load (obj->storage, obj, &err)) {
 		g_message ("couldn't load certificate at: %s: %s", 
 		           g_quark_to_string (obj->location),
 		           err && err->message ? err->message : "");
@@ -227,7 +227,7 @@
 	GkrPkObject *obj = GKR_PK_OBJECT (cert);
 	
 	/* Check if the index has such a value */
-	if (gkr_pk_index_has_value (obj, "purposes"))
+	if (gkr_pk_object_index_has_value (obj, "purposes"))
 		return TRUE;
 
 	if (gkr_pk_cert_has_extension (cert, OID_ENHANCED_USAGE, NULL))
@@ -249,10 +249,10 @@
 		return ret;
 			
 	*oids = NULL;
-	
+        
 	/* Look in the index if the purposes have been overridden there */	
-	if (gkr_pk_index_has_value (obj, "purposes")) {
-		*oids = gkr_pk_index_get_quarks (obj, "purposes");
+	if (gkr_pk_object_index_has_value (obj, "purposes")) {
+		*oids = gkr_pk_object_index_get_quarks (obj, "purposes");
 
 	/* Otherwise look in the certificate */		
 	} else {	
@@ -485,7 +485,7 @@
 		value = CKT_GNOME_UNKNOWN;
 		
 		/* Explicity set? */
-		index = gkr_pk_index_get_string (obj, "user-trust");
+		index = gkr_pk_object_index_get_string (obj, "user-trust");
 		if (index) {
 			if (g_str_equal (index, "trusted"))
 				value = CKT_GNOME_TRUSTED;

Modified: trunk/pk/gkr-pk-index.c
==============================================================================
--- trunk/pk/gkr-pk-index.c	(original)
+++ trunk/pk/gkr-pk-index.c	Mon Jul  7 21:17:26 2008
@@ -30,203 +30,36 @@
 #include "common/gkr-cleanup.h"
 #include "common/gkr-crypto.h"
 #include "common/gkr-location.h"
+#include "common/gkr-secure-memory.h"
 
-#include <sys/file.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define MAX_LOCK_TRIES 16
-
-#define GKR_TYPE_PK_INDEX             (gkr_pk_index_get_type())
-#define GKR_PK_INDEX(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), GKR_TYPE_PK_INDEX, GkrPkIndex))
-#define GKR_IS_PK_INDEX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), GKR_TYPE_PK_INDEX))
-
-typedef struct _GkrPkIndex      GkrPkIndex;
-typedef struct _GkrPkIndexClass GkrPkIndexClass;
-
-struct _GkrPkIndex {
-	 GObject parent;
-	 GHashTable *path_by_location;
-	 GHashTable *mtime_by_location;
-	 GHashTable *file_by_location;
-	 GHashTable *defaults_by_parent;
-};
+#include "keyrings/gkr-keyring-login.h"
+#include "keyrings/gkr-keyrings.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
 
-struct _GkrPkIndexClass {
-	GObjectClass parent_class;
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_KEYRING,
+	PROP_DEFAULTS
 };
 
-static GType gkr_pk_index_get_type (void);
 G_DEFINE_TYPE (GkrPkIndex, gkr_pk_index, G_TYPE_OBJECT);
 
-static GkrPkIndex *index_singleton = NULL; 
-static GQuark no_location = 0;
-
-typedef gboolean (*ReadValueFunc) (GKeyFile *file, const gchar *group, const gchar *field, 
-                                   GError **err, gpointer user_data);
-                                   
-typedef gboolean (*WriteValueFunc) (GKeyFile *file, const gchar *group, const gchar *field, 
-                                    GError **err, gpointer user_data);
+static GkrPkIndex *index_default = NULL; 
 
 /* -----------------------------------------------------------------------------
  * HELPERS
  */
- 
-#ifndef HAVE_FLOCK
-#define LOCK_SH 1
-#define LOCK_EX 2
-#define LOCK_NB 4
-#define LOCK_UN 8
-
-static int flock(int fd, int operation)
-{
-	struct flock flock;
-
-	switch (operation & ~LOCK_NB) {
-	case LOCK_SH:
-		flock.l_type = F_RDLCK;
-		break;
-	case LOCK_EX:
-		flock.l_type = F_WRLCK;
-		break;
-	case LOCK_UN:
-		flock.l_type = F_UNLCK;
-		break;
-	default:
-		errno = EINVAL;
-		return -1;
-	}
-
-	flock.l_whence = 0;
-	flock.l_start = 0;
-	flock.l_len = 0;
-
-	return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &flock);
-}
-#endif //NOT_HAVE_FLOCK
 
 static void 
-free_mtime (gpointer v)
-{
-	g_slice_free (time_t, v);
-}
-
-static GQuark* 
-quarks_from_strings (const gchar **strv, gsize *n_quarks)
+cleanup_default_index (void *unused)
 {
-	GArray *arr;
-	GQuark quark;
-	
-	arr = g_array_new (TRUE, TRUE, sizeof (GQuark));
-	while (*strv) {
-		quark = g_quark_from_string (*strv);
-		g_array_append_val (arr, quark);
-		++strv;
-	}
-	
-	if (n_quarks)
-		*n_quarks = arr->len;
-	
-	return (GQuark*)g_array_free (arr, FALSE);
-}
-
-static gchar**
-quarks_to_strings (const GQuark* quarks, gsize *n_strings)
-{
-	const gchar *value;
-	GArray *arr;
-	
-	arr = g_array_new (TRUE, TRUE, sizeof (const gchar*));
-	while (*quarks) {
-		value = g_quark_to_string (*quarks);
-		g_array_append_val (arr, value);
-		++quarks;
-	}
-	
-	if (n_strings)
-		*n_strings = arr->len;
-	return (gchar**)g_array_free (arr, FALSE);
-}
-
-static gboolean
-strings_are_equal (const gchar **one, const gchar **two)
-{
-	while (*one && *two) {
-		if (!g_str_equal (*one, *two))
-			return FALSE;
-		++one;
-		++two;
-	}
-	
-	return *one == *two;
-}
-
-static gpointer
-location_to_key (GQuark loc)
-{
-	return GUINT_TO_POINTER (loc ? loc : no_location);
-}
-
-static GQuark
-location_from_key (gpointer key)
-{
-	GQuark ret = GPOINTER_TO_UINT (key);
-	return ret == no_location ? 0 : ret;
-}
-
-static const gchar*
-index_path_for_location (GkrPkIndex *index, GQuark loc)
-{
-	gchar *locpath;
-	gchar *path;
-	
-	if (!loc)
-		return NULL; 
-	
-	path = g_hash_table_lookup (index->path_by_location, location_to_key (loc));
-	if (!path) {
-		locpath = gkr_location_to_path (loc);
-		if (!locpath) {
-			g_message ("The disk or drive this file is located on is not present: %s",
-			           g_quark_to_string (loc));
-			return NULL;
-		}
-		
-		/* Our index files have a .keystore extension */
-		path = g_strconcat (locpath, ".keystore", NULL);
-		g_free (locpath);
-		
-		g_hash_table_replace (index->path_by_location, location_to_key (loc), path);
-	}
-	
-	return path;
-}
-
-static gboolean
-check_index_mtime (GkrPkIndex *index, GQuark loc, time_t mtime)
-{
-	gpointer k;
-	gboolean ret = FALSE;
-	time_t *last;
-	
-	k = location_to_key (loc);
-	
-	/* Check on last mtime */
-	last = (time_t*)g_hash_table_lookup (index->mtime_by_location, k);
-	ret = !last || (*last != mtime);
-	
-	/* Setup new mtime */
-	if (ret) {
-		last = g_slice_new (time_t);
-		*last = mtime;
-		g_hash_table_replace (index->mtime_by_location, k, last);
-	}
-	
-	return ret;
+	g_assert (index_default);
+	g_object_unref (index_default);
+	index_default = NULL;
 }
 
 static gchar*
@@ -234,635 +67,218 @@
 {
 	const guchar *digdata;
 	gsize n_group, n_digdata;
-	gboolean r;
 	gchar *group;
+	gboolean r;
 	
-	g_return_val_if_fail (digest, NULL);
-		
+	/* Encode the digest */		
 	digdata = gkr_id_get_raw (digest, &n_digdata);
 	g_assert (digdata);
 	n_group = (n_digdata * 2) + 1;
 	group = g_malloc0 (n_group);
-	
 	r = gkr_crypto_hex_encode (digdata, n_digdata, group, &n_group);
 	g_assert (r == TRUE);
-	
-	return group;
-}
-
-static gboolean
-read_exists_any_value (GKeyFile *file, const gchar *group, const gchar *field,
-                       GError **err, gboolean *value)
-{
-	g_assert (value);
-	*value = g_key_file_has_group (file, group);
-	return TRUE;
-}
-
-static gboolean
-read_exists_value (GKeyFile *file, const gchar *group, const gchar *field, 
-                   GError **err, gboolean *value)
-{
-	g_assert (value);
-	g_assert (field);
-	*value = g_key_file_has_key (file, group, field, err);
-	return *err == NULL;	
-}
 
-static gboolean
-read_boolean_value (GKeyFile *file, const gchar *group, const gchar *field, 
-                    GError **err, gboolean *value)
-{
-	g_assert (value);
-	g_assert (field);
-	*value = g_key_file_get_boolean (file, group, field, err);
-	return *err == NULL;
-}
-
-static gboolean
-read_int_value (GKeyFile *file, const gchar *group, const gchar *field,
-                GError **err, gint *value)
-{
-	g_assert (value);
-	g_assert (field);
-	*value = g_key_file_get_integer (file, group, field, err);
-	return *err == NULL;
-}
-
-static gboolean
-read_string_value (GKeyFile *file, const gchar *group, const gchar *field,
-                   GError **err, gchar **value)
-{
-	g_assert (value);
-	g_assert (field);
-	*value = g_key_file_get_string (file, group, field, err);
-	return *value != NULL;
+	return group;
 }
-
+ 
 static gboolean
-read_quarks_value (GKeyFile *file, const gchar *group, const gchar *field,
-                   GError **err, GQuark **value)
+request_keyring_new (GQuark location, gchar **password)
 {
-	gchar **vals;
+	GkrAskRequest* ask;
+	gboolean ret;
 	
-	g_assert (value);
-	g_assert (field);
+	g_assert (password);
+	g_assert (!*password);
+
+	/* And put together the ask request */
+	ask = gkr_ask_request_new (_("Create Storage for Key Information"), 
+	                           _("Choose password to protect storage"),
+	 	                   GKR_ASK_REQUEST_NEW_PASSWORD);
 	
-	vals = g_key_file_get_string_list (file, group, field, NULL, err);
-	if (vals != NULL) {
-		g_assert (*err == NULL);
-		*value = quarks_from_strings ((const gchar**)vals, NULL);
-		g_strfreev (vals);
-		return TRUE;
-	}
+	gkr_ask_request_set_secondary (ask, _("The system wants to store information about your keys and certificates. "
+					      "In order to protect this information, choose a password with which it will be locked."));
 	
-	return FALSE;
-}
+	gkr_ask_request_set_location (ask, location);
 	
-static gint
-get_keyfile_value (GKeyFile *key_file, const gchar *group, 
-                   const gchar *field, ReadValueFunc func, gpointer data)
-{
-	GError *err = NULL;
-	
-	g_assert (key_file);
-	g_assert (group);
-	g_assert (func);
-	
-	if ((func) (key_file, group, field, &err, data))
-		return 1;
-	
-	if (err != NULL) {
-		if (err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND &&
-		    err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
-		    	g_warning ("couldn't read field '%s' from index: %s", 
-		    	           field, err->message ? err->message : "");
-			g_error_free (err);
-			return -1;
-		}
-		
-		g_error_free (err);
-	}
-
-	return 0;
+	/* And do the prompt */
+	gkr_ask_daemon_process (ask);
+	ret = ask->response >= GKR_ASK_RESPONSE_ALLOW;
+	if (ret)
+		*password = gkr_secure_strdup (ask->typed_password);
+	g_object_unref (ask);
+	return ret;
 }
 
 static gboolean
-write_clear (GKeyFile *file, const gchar *group, const gchar *field,
-             GError **err, gpointer user_data)
-{
-	if (!g_key_file_has_group (file, group))
-		return FALSE;
-	g_key_file_remove_group (file, group, err);
-	return TRUE; 	
-}
-
-static gboolean 
-write_delete (GKeyFile *file, const gchar *group, const gchar *field, 
-              GError **err, gpointer user_data)
+request_keyring_unlock (GkrPkIndex *index)
 {
-	g_assert (field);
+	GkrAskRequest* ask;
+	gboolean ret;
 	
-	if (g_key_file_has_key (file, group, field, err)) {
-		g_key_file_remove_key (file, group, field, err);
-		return TRUE;
-	}
+	g_return_val_if_fail (index->keyring, FALSE);
 	
-	return FALSE;
-}
-
-static gboolean 
-write_boolean_value (GKeyFile *file, const gchar *group, const gchar *field, 
-                     GError **err, gboolean *value)
-{
-	g_assert (value);
-	g_assert (field);
+	/* If the user denied access to this index, don't try again */
+	if (index->denied)
+		return FALSE;
 	
-	if (g_key_file_get_boolean (file, group, field, err) != *value || err != NULL) {
-		g_clear_error (err);
-		g_key_file_set_boolean (file, group, field, *value);
-		return TRUE;
-	}
+	/* And put together the ask request */
+	ask = gkr_ask_request_new (_("Unlock Storage for Key Information"), 
+	                           _("Enter password to unlock storage"),
+	                           GKR_ASK_REQUEST_PROMPT_PASSWORD);
 	
-	return FALSE;
-}
-
-static gboolean
-write_int_value (GKeyFile *file, const gchar *group, const gchar *field, 
-                 GError **err, gint *value)
-{
-	g_assert (value);
-	g_assert (field);
+	gkr_ask_request_set_secondary (ask, _("The system wants to access information about your keys and certificates, "
+					      "but it is locked."));
 	
-	if (g_key_file_get_integer (file, group, field, err) != *value || err != NULL) {
-		g_clear_error (err);
-		g_key_file_set_integer (file, group, field, *value);
-		return TRUE;
-	}
+	gkr_ask_request_set_location (ask, index->keyring->location);
+	gkr_ask_request_set_object (ask, G_OBJECT (index->keyring));
 	
-	return FALSE;
-}
+	if (gkr_keyring_login_is_usable ())
+		gkr_ask_request_set_check_option (ask, _("Automatically unlock this keyring when I log in."));
 
-static gboolean
-write_string_value (GKeyFile *file, const gchar *group, const gchar *field, 
-                    GError **err, const gchar **value)
-{
-	gboolean ret = FALSE;
-	gchar *o;
+	/* Intercept item access requests to see if we still need to prompt */
+	g_signal_connect (ask, "check-request", G_CALLBACK (gkr_keyring_ask_check_unlock), NULL);
+	gkr_ask_daemon_process (ask);
 	
-	g_assert (value);
-	g_assert (*value);
-	g_assert (field);
-	
-	o = g_key_file_get_value (file, group, field, NULL);
-
-	if (!o || !g_str_equal (o, *value)) {
-		g_key_file_set_string (file, group, field, *value);
-		ret = TRUE;
+	ret = ask->response >= GKR_ASK_RESPONSE_ALLOW;
+	if (ask->response == GKR_ASK_RESPONSE_DENY) {
+		g_message ("access to the pk index was denied");
+		index->denied = TRUE;
 	}
-			
-	g_free (o);
-	return ret;
-}
-
-static gboolean
-write_quarks_value (GKeyFile *file, const gchar *group, const gchar *field, 
-                    GError **err, GQuark **value)
-{
-	GQuark *quarks;
-	gsize n_strings;
-	gchar **strings, **o;
-	gboolean ret = FALSE;
-	
-	g_assert (value);
-	g_assert (*value);
-	g_assert (field);
-	
-	quarks = *value;
-	strings = quarks_to_strings (quarks, &n_strings);
-	o = g_key_file_get_string_list (file, group, field, NULL, NULL);
-		
-	if (!o || !strings_are_equal ((const gchar**)strings, (const gchar**)o)) {
-		g_key_file_set_string_list (file, group, field, (const gchar**)strings, n_strings);
-		ret = TRUE;
-	}
-		
-	g_strfreev (o);
-	g_free (strings);
+	
+	g_object_unref (ask);
 	return ret;
 }
 
-static void
-set_keyfile_value (GKeyFile *key_file, gkrconstid digest, 
-                   const gchar *field, WriteValueFunc func, 
-                   gpointer data, gboolean *updated)
+static GkrKeyringItem*
+find_item_for_digest (GkrPkIndex *index, gkrconstid digest, gboolean create)
 {
-	GError *err = NULL;
+	GnomeKeyringAttributeList *attrs;
+	GkrKeyringItem *item;
 	gchar *group;
+	guint type;
 	
-	g_assert (key_file);
-	g_assert (digest);
-	g_assert (func);
-	g_assert (updated);
-	
-	/* TODO: Cache this somehow? */
-	group = digest_to_group (digest);
-	g_return_if_fail (group);
-	
-	*updated = (func) (key_file, group, field, &err, data);
+	g_return_val_if_fail (index && index->keyring, NULL);
+	g_return_val_if_fail (digest, NULL);
 
-	if (err) {
-	    	g_warning ("couldn't write field '%s' to index: %s", 
-	    	           field, err->message ? err->message : "");
-		g_error_free (err);
+	/* Unlock the keyring if necassary */
+	if (index->keyring->locked) {
+		if (!request_keyring_unlock (index))
+			return NULL;
+		g_return_val_if_fail (index->keyring->locked == FALSE, NULL);
 	}
 	
-	g_free (group);
-}	
-
-static GKeyFile*
-read_key_file (int fd, GError **err)
-{
-	GKeyFile *key_file = NULL;
-	gchar *contents;
-	gboolean res;
-	struct stat sb;
-		
-	g_assert (fd != -1);
-	
-	if (fstat (fd, &sb) == -1) {
-		g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (errno),
-		             "failed to get index file size: %s", g_strerror (errno));
-		return NULL;		
-	}
-
-	/* Empty file, empty key file */
-	if (sb.st_size == 0 || sb.st_size > G_MAXSIZE)
-		return g_key_file_new ();
-				
-	contents = (gchar*)mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	if (!contents) {
-		g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (errno),
-		             "failed to read (map) index file: %s", g_strerror (errno));
-		return NULL;
-	}
-		
-	key_file = g_key_file_new ();
-	res = g_key_file_load_from_data (key_file, contents, sb.st_size, G_KEY_FILE_KEEP_COMMENTS, err);
-	munmap (contents, sb.st_size);
-
-	if (!res) {	
-		g_key_file_free (key_file);
-		key_file = NULL;
-	}
+	group = digest_to_group (digest);
 	
-	return key_file;
-}
-			
-static GKeyFile*
-load_index_key_file (GkrPkIndex *index, GQuark loc, int fd, gboolean force)
-{
-	GKeyFile *key_file = NULL;
-	const gchar *path;
-	gboolean closefd = FALSE;
-	GError *err = NULL;
-	
-	/* If we've never seen it then we should try to read it */
-	if (loc && !force && 
-	    !g_hash_table_lookup (index->file_by_location, location_to_key (loc)))
-		force = TRUE;
-		
-	/* Read it when necessary and possible */
-	if (force) {
-		path = index_path_for_location (index, loc);
-		if (path) {
-			fd = open (path, O_RDONLY);
-			if (fd == -1) {
-				if (errno != ENOTDIR && errno != ENOENT) {
-					g_message ("couldn't open index file: %s: %s", 
-				        	   path, g_strerror (errno));
-					return NULL;
-				}
-			}
-			
-			closefd = TRUE;
-		}
-
-		/* No file on disk, no index */
-		if (fd == -1) {
-			g_hash_table_remove (index->file_by_location, 
-			                     location_to_key (loc));
-			                     
-		/* Read in the open file */
-		} else {
-			key_file = read_key_file (fd, &err);
-			if (closefd)
-				close (fd);
-				
-			if (!key_file) {
-				g_message ("couldn't read index file: %s: %s", path ? path : "", 
-				            err && err->message ? err->message : "");
-				return NULL;
-			}
-			
-			g_hash_table_replace (index->file_by_location, 
-			                      location_to_key (loc), key_file);
-		}
-	}
+	attrs = gnome_keyring_attribute_list_new ();
+	gnome_keyring_attribute_list_append_string (attrs, "object-digest", group);
+	item = gkr_keyring_find_item (index->keyring, GNOME_KEYRING_ITEM_PK_STORAGE, attrs, FALSE);
 	
-	key_file = g_hash_table_lookup (index->file_by_location,
-	                                location_to_key (loc));
-
-	/* Automatically create an in memory key file for 'no location' */
-	if (!key_file && !loc) {
-		key_file = g_key_file_new ();
-		g_hash_table_replace (index->file_by_location,
-		                      location_to_key (loc), key_file);
+	if (item || !create) {
+		gnome_keyring_attribute_list_free (attrs);
+		g_free (group);
+		return item;  
 	}
 
-	/* No index is available for this location */
-	if (!key_file)
-		return NULL;
-
-	return key_file;
-}
+	type = GNOME_KEYRING_ITEM_PK_STORAGE | GNOME_KEYRING_ITEM_APPLICATION_SECRET;
+	item = gkr_keyring_item_create (index->keyring, type);
 
-static const gchar*
-find_parent_defaults (GQuark parent)
-{
-	const GkrPkPlace *place;
-	const gchar *defaults = NULL;
-	GSList *volumes, *l;
-	GQuark loc;
-	guint i;
+	gkr_keyring_add_item (index->keyring, item);
+	g_object_unref (item);
 	
-	for (i = 0; i < G_N_ELEMENTS (gkr_pk_places); ++i) {
-		place = &(gkr_pk_places[i]);
-		
-		/* With a specific volume */
-		if (place->volume) {
-			loc = gkr_location_from_string (place->volume);
-			loc = gkr_location_from_child (loc, place->directory);
-			if (loc == parent)
-				defaults = place->defaults;
-				
-		/* With any volume */
-		} else {
-			volumes = gkr_location_manager_get_volumes (NULL);
-			for (l = volumes; l; l = g_slist_next (l)) {
-				loc = gkr_location_from_child (GPOINTER_TO_UINT (l->data), 
-				                               place->directory);
-				if (loc == parent) {
-					defaults = place->defaults;
-					break;
-				}
-			}
-			g_slist_free (volumes);
-		}
-		
-		/* Found something? */
-		if (defaults)
-			return defaults;
-	}
+	gnome_keyring_attribute_list_free (item->attributes);
+	item->attributes = attrs;
+	g_free (group);
 	
-	return NULL;	
+	return item;
 }
 
-static GKeyFile*
-load_parent_key_file (GkrPkIndex *index, GQuark loc)
+static GnomeKeyringAttribute*
+find_default_attribute (GkrPkIndex *index, const gchar *field)
 {
-	GKeyFile *file;
-	GQuark parent;
-	const gchar *defaults;
-	
-	if (!loc)
-		return NULL;
-		
-	parent = gkr_location_to_parent (loc);
-	if (!parent)
+	if (!index->defaults)
 		return NULL;
-		
-	file = g_hash_table_lookup (index->defaults_by_parent, GUINT_TO_POINTER (parent));
-	if (!file) {
-		file = g_key_file_new ();
-		g_hash_table_insert (index->defaults_by_parent, GUINT_TO_POINTER (parent), file);	
-
-		/* 
-		 * Look in the places list and load any default index data 
-		 * from there. 
-		 */
-		defaults = find_parent_defaults (parent);
-		if (defaults) {
-			if (!g_key_file_load_from_data (file, defaults, strlen (defaults), 
-			                                G_KEY_FILE_NONE, NULL))
-				g_warning ("couldn't parse builtin parent defaults");
-		}
-	}
-	
-	return file;
+	return gkr_attribute_list_find (index->defaults, field);
 }
 
 static gboolean
-read_pk_index_value (GkrPkIndex *index, GQuark loc, gkrconstid digest, 
-                     const gchar *field, GkrPkObject *object, 
-                     ReadValueFunc func, gpointer data)
-{
-	const gchar *path = NULL;
-	struct stat sb;
-	gboolean force = FALSE;
-	GKeyFile *key_file = NULL;
-	gchar *group;
-	gint ret = 0;
-	
-	g_return_val_if_fail (digest, FALSE);
-
-	if (loc) {
-		path = index_path_for_location (index, loc);
-		if (!path) 
-			return FALSE;
+string_equal (const gchar *one, const gchar *two)
+{
+	if (!one && !two)
+		return TRUE;
+	if (!one || !two)
+		return FALSE;
+	return strcmp (one, two) == 0;
+}
 
-		/* TODO: Any way to do this less often? */
-		force = (stat (path, &sb) < 0 || check_index_mtime (index, loc, sb.st_mtime));
-	}
-	
-	key_file = load_index_key_file (index, loc, -1, force);
-	
-	/* Try the actual item first */
-	if (key_file) {
-		group = digest_to_group (digest);
-		g_return_val_if_fail (group, FALSE);
+static gboolean 
+write_string (GkrPkIndex *index, gkrconstid digest, const gchar *field, 
+              const gchar *val)
+{
+	GnomeKeyringAttribute *prev;
+	GnomeKeyringAttribute attr;
+	GkrKeyringItem *item;
 	
-		ret = get_keyfile_value (key_file, group, field, func, data);
-		g_free (group);
+	if (!index)
+		index = gkr_pk_index_default ();
 
-		/* If not found, look in the default section */
-		if (ret == 0)
-			ret = get_keyfile_value (key_file, "default", field, func, data);
-	}
-		
-	/* Look in the parent directory defaults */
-	if (ret == 0) {
-		key_file = load_parent_key_file (index, loc);
-		if (key_file) 
-			ret = get_keyfile_value (key_file, "default", field, func, data);
-	}
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+	g_return_val_if_fail (field != NULL, FALSE);
 
-	/* 
-	 * If we saw that the file was changed, then tell the object
-	 * to flush all of its caches and etc...
-	 */ 
-	if (force && object)
-		gkr_pk_object_flush (object);
+	item = find_item_for_digest (index, digest, TRUE);
+	if (!item)
+		return FALSE;
 	
-	return ret == 1;
-}
-
-static gboolean
-update_pk_index_value (GkrPkIndex *index, GQuark loc, gkrconstid digest, 
-                       const gchar *field, GkrPkObject *object, 
-                       WriteValueFunc func, gpointer data)
-{
-	const gchar *path = NULL;
-	gchar *contents = NULL;
-	gboolean ret = FALSE;
-	gboolean force = FALSE;
-	gboolean updated = FALSE;
-	GError *err = NULL;
-	GKeyFile *key_file = NULL;
-	gsize n_contents;
-	struct stat sb;
-	int tries = 0;
-	int fd = -1;
-	
-	g_return_val_if_fail (digest, FALSE);
-	
-	if (loc) {
-		path = index_path_for_location (index, loc);
-		if (!path) 
+	/* Skip this step if we already have this value */
+	prev = gkr_attribute_list_find (item->attributes, field);
+	if (prev) {
+		if (prev->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING && 
+		    string_equal (prev->value.string, val))
 			return FALSE;
-	
-		/* File lock retry loop */
-		for (;;) {
-			if (tries > MAX_LOCK_TRIES) {
-				g_message ("couldn't write index '%s' value to file: %s: file is locked", 
-			        	   field, path);
-				goto done;
-			}
-			
-			fd = open (path, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
-			if (fd == -1) {
-				g_message ("couldn't create index file: %s: %s", path, g_strerror (errno));
-				goto done;
-			}
-			
-			if (flock (fd, LOCK_EX | LOCK_NB) < 0) {
-				if (errno == EWOULDBLOCK) {
-					close (fd);
-					fd = -1;
-					++tries;
-					gkr_async_usleep (200000);
-					continue;
-				} 
-				g_message ("couldn't lock index file: %s: %s", path, g_strerror (errno));
-				goto done;
-			}
-			
-			/* Successfully opened file */;
-			break;
-		}
-
-	
-		/* See if file needs updating */
-		force = (fstat (fd, &sb) < 0 || check_index_mtime (index, loc, sb.st_mtime));
-	}
-	
-	key_file = load_index_key_file (index, loc, -1, force);
-	if (!key_file)
-		goto done;
-
-	set_keyfile_value (key_file, digest, field, func, data, &updated);
-	if (updated && loc) {
-		
-		/* Serialize the key file into memory */
-		contents = g_key_file_to_data (key_file, &n_contents, &err);
-		if (!contents) {
-			g_warning ("couldn't serialize index file: %s", 
-			           err && err->message ? err->message : "");
-			g_error_free (err);
-			goto done;
-		}
-		
-		g_assert (path);
-		
-		/* And write that memory to disk atomically */
-		if (!g_file_set_contents (path, contents, n_contents, &err)) {
-			g_message ("couldn't write index file to disk: %s: %s", 
-			           path, err && err->message ? err->message : "");
-			g_error_free (err);
-			goto done;
-		}
 	}
-	
-	/* 
-	 * If the file was updated then tell the object to flush all of 
-	 * its caches and other optimizations...
-	 */
-	if ((force || updated) && object)
-		gkr_pk_object_flush (object);
 		
-	ret = TRUE;
-	
-done:
-	if (fd != -1)
-		close (fd);
-	g_free (contents);
-	
-	return ret;	
-}
-
-static void 
-cleanup_index_singleton (void *unused)
-{
-	g_assert (index_singleton);
-	g_object_unref (index_singleton);
-	index_singleton = NULL;
+	attr.name = (gchar*)field;
+	attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+	attr.value.string = (gchar*)val;
+	
+	gkr_attribute_list_set (item->attributes, &attr);
+	if (!gkr_keyring_save_to_disk (index->keyring))
+		g_warning ("writing field '%s': couldn't write index keyring to disk", field);
+	return TRUE;
 }
 
-static GkrPkIndex*
-get_index_singleton (void)
+static gboolean 
+write_uint (GkrPkIndex *index, gkrconstid digest, const gchar *field, guint val) 
 {
-	if (!index_singleton) {
-		index_singleton = g_object_new (GKR_TYPE_PK_INDEX, NULL);
-		gkr_cleanup_register (cleanup_index_singleton, NULL);
-	}
+	GnomeKeyringAttribute *prev;
+	GnomeKeyringAttribute attr;
+	GkrKeyringItem *item;
 	
-	return index_singleton;
-}
+	if (!index)
+		index = gkr_pk_index_default ();
 
-static gboolean
-remove_descendent_locations (gpointer key, gpointer value, gpointer user_data)
-{
-	GQuark loc = location_from_key (key);
-	GQuark volume = GPOINTER_TO_UINT (user_data);
-	return loc && gkr_location_is_descendant (volume, loc);
-}
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+	g_return_val_if_fail (field != NULL, FALSE);
 
-static void
-flush_caches (GkrLocationManager *locmgr, GQuark volume, GkrPkIndex *index)
-{
-	/* 
-	 * Called when the location manager adds or removes a prefix
-	 * possibly invalidating our cached paths.
-	 */
-	
-	g_hash_table_foreach_remove (index->path_by_location, remove_descendent_locations, 
-	                             GUINT_TO_POINTER (volume));
-	g_hash_table_foreach_remove (index->file_by_location, remove_descendent_locations, 
-	                             GUINT_TO_POINTER (volume));
-	g_hash_table_foreach_remove (index->mtime_by_location, remove_descendent_locations, 
-	                             GUINT_TO_POINTER (volume));
-	g_hash_table_foreach_remove (index->defaults_by_parent, remove_descendent_locations,
-	                             GUINT_TO_POINTER (volume));
+	item = find_item_for_digest (index, digest, TRUE);
+	if (!item)
+		return FALSE;
+	
+	/* Skip this step if we already have this value */
+	prev = gkr_attribute_list_find (item->attributes, field);
+	if (prev) {
+		if (prev->type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 &&
+		    prev->value.integer == val)
+			return FALSE;
+	}
+		
+	attr.name = (gchar*)field;
+	attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32;
+	attr.value.integer = val;
+	
+	gkr_attribute_list_set (item->attributes, &attr);
+	if (!gkr_keyring_save_to_disk (index->keyring))
+		g_warning ("writing field '%s': couldn't write index keyring to disk", field);
+	return TRUE;
 }
 
 /* -----------------------------------------------------------------------------
@@ -872,39 +288,60 @@
 static void
 gkr_pk_index_init (GkrPkIndex *index)
 {
-	GkrLocationManager *locmgr;
-	
-	index->path_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); 
-	index->mtime_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, free_mtime);
-	index->file_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
-	                                                 (GDestroyNotify)g_key_file_free);
-	index->defaults_by_parent = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
-	                                                   (GDestroyNotify)g_key_file_free);
-	
-	locmgr = gkr_location_manager_get ();
-	g_signal_connect (locmgr, "volume-removed", G_CALLBACK (flush_caches), index);
+
 }
 
 static void
 gkr_pk_index_finalize (GObject *obj)
 {
 	GkrPkIndex *index = GKR_PK_INDEX (obj);
-	GkrLocationManager *locmgr;
 	
-	locmgr = gkr_location_manager_get ();
-	g_signal_handlers_disconnect_by_func (locmgr, flush_caches, index);
+	g_object_unref (index->keyring);
+	index->keyring = NULL;
 	
-	g_hash_table_destroy (index->path_by_location);
-	g_hash_table_destroy (index->mtime_by_location);
-	g_hash_table_destroy (index->file_by_location);
-	g_hash_table_destroy (index->defaults_by_parent);
-	index->path_by_location = index->mtime_by_location = NULL;
-	index->file_by_location = index->defaults_by_parent = NULL;
+	gnome_keyring_attribute_list_free (index->defaults);
+	index->defaults = NULL;
 	
 	G_OBJECT_CLASS (gkr_pk_index_parent_class)->finalize (obj);
 }
 
 static void
+gkr_pk_index_get_property (GObject *obj, guint prop_id, GValue *value, 
+                           GParamSpec *pspec)
+{
+	GkrPkIndex *index = GKR_PK_INDEX (obj);
+
+	switch (prop_id) {
+	case PROP_KEYRING:
+		g_value_set_object (value, index->keyring);
+		break;
+	case PROP_DEFAULTS:
+		g_value_set_pointer (value, index->defaults); 
+		break;
+	}
+}
+
+static void
+gkr_pk_index_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                           GParamSpec *pspec)
+{
+	GkrPkIndex *index = GKR_PK_INDEX (obj);
+	
+	switch (prop_id) {
+	case PROP_KEYRING:
+		g_return_if_fail (GKR_IS_KEYRING (g_value_get_object (value)));
+		g_return_if_fail (!index->keyring);
+		index->keyring = GKR_KEYRING (g_value_get_object (value));
+		g_object_ref (index->keyring);
+		break;
+	case PROP_DEFAULTS:
+		g_return_if_fail (!index->defaults);
+		index->defaults = gnome_keyring_attribute_list_copy (g_value_get_pointer (value));
+		break;
+	}
+}
+
+static void
 gkr_pk_index_class_init (GkrPkIndexClass *klass)
 {
 	GObjectClass *gobject_class;
@@ -913,230 +350,336 @@
 
 	gobject_class = (GObjectClass*)klass;
 	gobject_class->finalize = gkr_pk_index_finalize;
+	gobject_class->get_property = gkr_pk_index_get_property;
+	gobject_class->set_property = gkr_pk_index_set_property;
 	
-	/* A special quark that denotes stored in memory */
-	no_location = g_quark_from_static_string ("MEMORY");
+	g_object_class_install_property (gobject_class, PROP_KEYRING,
+		g_param_spec_object ("keyring", "Keyring", "Keyring the index writes to",
+		                     GKR_TYPE_KEYRING, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (gobject_class, PROP_DEFAULTS,
+		g_param_spec_pointer ("defaults", "Defaults", "Default index attributes",
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 /* -----------------------------------------------------------------------------
  * PUBLIC
  */
 
-gboolean
-gkr_pk_index_get_boolean (GkrPkObject *obj, const gchar *field, gboolean defvalue)
+GkrPkIndex*
+gkr_pk_index_new (GkrKeyring *keyring, GnomeKeyringAttributeList *defaults)
 {
-	gboolean ret = defvalue;
+	GkrPkIndex *index;
+	gpointer unref = NULL;
 	
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), ret);
-	g_return_val_if_fail (field != NULL, ret);	
+	if (!keyring)
+		unref = keyring = gkr_keyring_new ("in-memory", 0);
+	g_return_val_if_fail (GKR_IS_KEYRING (keyring), NULL);
 	
-	if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
-	                          field, obj, (ReadValueFunc)read_boolean_value, &ret))
-		ret = defvalue;
-
-	return ret;
+	index = g_object_new (GKR_TYPE_PK_INDEX, "keyring", keyring, 
+	                      "defaults", defaults, NULL);
+	
+	if (unref)
+		g_object_unref (unref);
+	return index;
 }
 
-gboolean
-gkr_pk_index_get_boolean_full (GQuark location, gkrconstid digest, 
-                               const gchar *field, gboolean defvalue)
+
+GkrPkIndex*
+gkr_pk_index_open (GQuark index_location, const gchar *name, 
+                   GnomeKeyringAttributeList *defaults)
 {
-	gboolean ret = defvalue;
+	GkrKeyring *keyring, *login;
+	gchar *password;
 	
-	g_return_val_if_fail (digest, ret);
-	g_return_val_if_fail (field != NULL, ret);
+	keyring = gkr_keyrings_for_location (index_location);
 	
-	if (!read_pk_index_value (get_index_singleton (), location, digest, field,
-	                          NULL, (ReadValueFunc)read_boolean_value, &ret))
-		ret = defvalue;
+	/* No keyring, try and create one */
+	if (!keyring) {
+		
+		/* We need a password, see if we can use the login one */
+		password = NULL;
+		if (gkr_keyring_login_unlock (NULL)) {
+			if (gkr_keyring_login_is_usable ()) {
+				login = gkr_keyrings_get_login ();
+				if (login)
+					password = gkr_secure_strdup (login->password);
+			}
+		}
+		
+		/* We need to prompt for a password */
+		if (!password) {
+			if (!request_keyring_new (index_location, &password))
+				return NULL;
+		}
+		
+		g_return_val_if_fail (password, NULL);
+		
+		keyring = gkr_keyring_create (index_location, name, password);
+		gkr_secure_strfree (password);
 
-	return ret;
+		/* Make it available */
+		gkr_keyrings_add (keyring);
+		g_object_unref (keyring);
+	}
+	
+	return gkr_pk_index_new (keyring, defaults);
 }
 
-gint
-gkr_pk_index_get_int (GkrPkObject *obj, const gchar *field, gint defvalue)
+GkrPkIndex*
+gkr_pk_index_default (void)
 {
-	gint ret = defvalue;
+	if (!index_default) {
+		index_default = gkr_pk_index_new (NULL, NULL);
+		gkr_cleanup_register (cleanup_default_index, NULL);
+	}
 	
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), ret);	
-	g_return_val_if_fail (field != NULL, ret);	
+	return index_default;
+}
 
-	if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
-	                          field, obj, (ReadValueFunc)read_int_value, &ret))
-		ret = defvalue;
+gboolean
+gkr_pk_index_get_boolean (GkrPkIndex *index, gkrconstid digest, 
+                          const gchar *field, gboolean defvalue)
+{
+	return gkr_pk_index_get_uint (index, digest, field, defvalue ? 1 : 0) ? 
+			TRUE : FALSE;
+}
+
+guint
+gkr_pk_index_get_uint (GkrPkIndex *index, gkrconstid digest, 
+                       const gchar *field, guint defvalue)
+{
+	GnomeKeyringAttribute *attr = NULL;
+	GkrKeyringItem *item;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
+	
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), defvalue);
 
-	return ret;	
+	item = find_item_for_digest (index, digest, FALSE);
+	if (item != NULL)
+		attr = gkr_attribute_list_find (item->attributes, field);
+		
+	attr = gkr_attribute_list_find (item->attributes, field);
+	if (!attr) {
+		attr = find_default_attribute (index, field);
+		if (!attr)
+			return defvalue;
+	}
+		
+	g_return_val_if_fail (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32, defvalue);
+	return attr->value.integer;
 }                                                                 
 
 gchar*
-gkr_pk_index_get_string (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_get_string (GkrPkIndex *index, gkrconstid digest, const gchar *field)
 {
-	gchar *ret = NULL;
+	GnomeKeyringAttribute *attr = NULL;
+	GkrKeyringItem *item;
 	
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), NULL);
-	g_return_val_if_fail (field != NULL, NULL);	
+	if (!index)
+		index = gkr_pk_index_default ();
 	
-	if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
-	                          field, obj, (ReadValueFunc)read_string_value, &ret))
-		ret = NULL;
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), NULL);
 
-	return ret;
+	item = find_item_for_digest (index, digest, FALSE);
+	if (item != NULL)
+		attr = gkr_attribute_list_find (item->attributes, field);
+		
+	if (!attr) {
+		attr = find_default_attribute (index, field);
+		if (!attr)
+			return NULL;
+	}
+		
+	g_return_val_if_fail (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, NULL);
+	return g_strdup (attr->value.string);
 }
 
 gchar*
-gkr_pk_index_get_string_full (GQuark location, gkrconstid digest, 
-                              const gchar *field)
+gkr_pk_index_get_secret (GkrPkIndex *index, gkrconstid digest)
 {
-	gchar *ret = NULL;
-	
-	g_return_val_if_fail (digest, NULL);
-	g_return_val_if_fail (field != NULL, NULL);	
+	GkrKeyringItem *item;
 	
-	if (!read_pk_index_value (get_index_singleton (), location, digest, field,
-	                          NULL, (ReadValueFunc)read_string_value, &ret))
-		ret = NULL;
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), NULL);
 
-	return ret;	
+	item = find_item_for_digest (index, digest, FALSE);
+	if (item == NULL)
+		return NULL;
+		
+	return gkr_secure_strdup (item->secret);	
 }
 
 guchar*
-gkr_pk_index_get_binary (GkrPkObject *obj, const gchar *field, gsize *n_data)
+gkr_pk_index_get_binary (GkrPkIndex *index, gkrconstid digest, 
+                         const gchar *field, gsize *n_data)
 {
 	guchar *data;
-	gchar *str;
-	gsize n_str;
+	gchar *string;
+	gsize n_string;
+
+	if (!index)
+		index = gkr_pk_index_default ();
 
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), NULL);
-	g_return_val_if_fail (field != NULL, NULL);	
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+	g_return_val_if_fail (field != NULL, FALSE);
 	g_return_val_if_fail (n_data != NULL, NULL);	
 
-	str = gkr_pk_index_get_string (obj, field);
-	if (!str)
+	string = gkr_pk_index_get_string (index, digest, field);
+	if (!string)
 		return NULL;
 		
-	n_str = strlen (str);
-	*n_data = (n_str / 2) + 1;
+	n_string = strlen (string);
+	*n_data = (n_string / 2) + 1;
 	data = g_malloc0 (*n_data);
-	if (!gkr_crypto_hex_decode (str, n_str, data, n_data)) {
+	if (!gkr_crypto_hex_decode (string, n_string, data, n_data)) {
 		g_message ("invalid binary data in index under field '%s'", field);
 		g_free (data);
 		data = NULL;
 	}
 
-	g_free (str);
-	return data;	
+	g_free (string);
+	return data;
 }
 
 GQuark* 
-gkr_pk_index_get_quarks (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_get_quarks (GkrPkIndex *index, gkrconstid digest, 
+                         const gchar *field)
 {
-	GQuark *ret = NULL;
+	GArray *quarks;
+	GQuark quark;
+	gchar *string; 
+	gchar *at, *next;
 	
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), NULL);
-	g_return_val_if_fail (field != NULL, NULL);	
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+	g_return_val_if_fail (field != NULL, FALSE);
+	
+	string = gkr_pk_index_get_string (index, digest, field);
+	if (!string)
+		return NULL;
 	
-	if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
-	                          field, obj, (ReadValueFunc)read_quarks_value, &ret))
-		ret = NULL;
+	quarks = g_array_new (TRUE, TRUE, sizeof (GQuark));
 		
-	return ret;
+	/* Parse all the quarks */
+	at = string;
+	while (at != NULL) {
+		next = strchr (at, '\n');
+		if (next) {
+			*next = 0;
+			++next;
+		}
+		
+		quark = g_quark_from_string (at);
+		g_array_append_val (quarks, quark);
+		at = next;
+	}
+	
+	g_free (string);
+	return (GQuark*)g_array_free (quarks, FALSE);
 }
 
 gboolean
-gkr_pk_index_has_value (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_has_value (GkrPkIndex *index, gkrconstid digest, 
+                        const gchar *field)
 {
-	gboolean ret;
+	GkrKeyringItem *item;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
 
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
 	g_return_val_if_fail (field != NULL, FALSE);
-	
-	if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
-	                          field, obj, (ReadValueFunc)read_exists_value, &ret))
-		ret = FALSE;
 
-	return ret;
+	item = find_item_for_digest (index, digest, FALSE);
+	if (!item)
+		return index->defaults && gkr_attribute_list_find (index->defaults, field);
+		
+	return gkr_attribute_list_find (item->attributes, field) ? TRUE : FALSE;
 }
 
 gboolean
-gkr_pk_index_have (GkrPkObject *obj)
+gkr_pk_index_have (GkrPkIndex *index, gkrconstid digest)
 {
-	gboolean ret;
-
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	GkrKeyringItem *item;
 	
-	if (!read_pk_index_value (get_index_singleton (), obj->location, obj->digest,
-	                          NULL, obj, (ReadValueFunc)read_exists_any_value, &ret))
-		ret = FALSE;
-
-	return ret;
-}
+	if (!index)
+		index = gkr_pk_index_default ();
 
-gboolean
-gkr_pk_index_have_full (GQuark location, gkrconstid digest)
-{
-	gboolean ret;
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
 
-	g_return_val_if_fail (digest, FALSE);
-	
-	if (!read_pk_index_value (get_index_singleton (), location, digest, NULL,
-	                          NULL, (ReadValueFunc)read_exists_any_value, &ret))
-		ret = FALSE;
-
-	return ret;
+	item = find_item_for_digest (index, digest, FALSE);
+	return item == NULL ? FALSE : TRUE;
 }
 
 gboolean
-gkr_pk_index_set_boolean (GkrPkObject *obj, const gchar *field, gboolean val)
+gkr_pk_index_set_boolean (GkrPkIndex *index, gkrconstid digest, 
+                          const gchar *field, gboolean val)
 {
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
-	g_return_val_if_fail (field != NULL, FALSE);
-		
-	return update_pk_index_value (get_index_singleton (), obj->location, obj->digest, 
-	                              field, obj, (WriteValueFunc)write_boolean_value, &val);
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	return write_uint (index, digest, field, val ? 1 : 0);
 }
 
 gboolean
-gkr_pk_index_set_int (GkrPkObject *obj, const gchar *field, gint val)
+gkr_pk_index_set_uint (GkrPkIndex *index, gkrconstid digest, 
+                       const gchar *field, guint val)
 {
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
-	g_return_val_if_fail (field != NULL, FALSE);
-
-	return update_pk_index_value (get_index_singleton (), obj->location, obj->digest, 
-	                              field, obj, (WriteValueFunc)write_int_value, &val);
-}                                                       
+	return write_uint (index, digest, field, val);
+}                              
                                                         
 gboolean 
-gkr_pk_index_set_string (GkrPkObject *obj, const gchar *field, const gchar *val)
+gkr_pk_index_set_string (GkrPkIndex *index, gkrconstid digest, 
+                         const gchar *field, const gchar *val)
 {
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
-	g_return_val_if_fail (field != NULL, FALSE);
-	g_return_val_if_fail (val, FALSE);
-
-	return update_pk_index_value (get_index_singleton (), obj->location, obj->digest, 
-	                              field, obj, (WriteValueFunc)write_string_value, &val);
+	return write_string (index, digest, field, val);
 }
 
-gboolean
-gkr_pk_index_set_string_full (GQuark location, gkrconstid digest, const gchar *field, 
-                              const gchar *val)
+gboolean 
+gkr_pk_index_set_secret (GkrPkIndex *index, gkrconstid digest, 
+                         const gchar *val)
 {
-	g_return_val_if_fail (digest, FALSE);
-	g_return_val_if_fail (field != NULL, FALSE);
-	g_return_val_if_fail (val, FALSE);
+	GkrKeyringItem *item;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
 
-	return update_pk_index_value (get_index_singleton (), location, digest, field, 
-	                              NULL, (WriteValueFunc)write_string_value, &val);	
+	item = find_item_for_digest (index, digest, TRUE);
+	if (!item)
+		return FALSE;
+
+	/* Make sure it's actually changed */
+	if (string_equal (item->secret, val))
+		return FALSE;
+	
+	gkr_secure_strfree (item->secret);
+	item->secret = gkr_secure_strdup (val);
+	if (!gkr_keyring_save_to_disk (index->keyring))
+		g_warning ("writing secret: couldn't write index keyring to disk");
+	return TRUE;
 }
 
 gboolean
-gkr_pk_index_set_binary (GkrPkObject *obj, const gchar *field, 
-                         const guchar *data, gsize n_data)
+gkr_pk_index_set_binary (GkrPkIndex *index, gkrconstid digest, 
+                         const gchar *field, const guchar *data, 
+                         gsize n_data)
 {
 	gboolean ret, r;
 	gchar *str;
 	gsize n_str;
 	
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
 	g_return_val_if_fail (field != NULL, FALSE);
 	g_return_val_if_fail (data != NULL, FALSE);
 	
@@ -1146,44 +689,157 @@
 	r = gkr_crypto_hex_encode (data, n_data, str, &n_str);
 	g_assert (r == TRUE);
 	
-	ret = gkr_pk_index_set_string (obj, field, str);
+	ret = write_string (index, digest, field, str);
 	g_free (str);
 
 	return ret;
 }
 
 gboolean
-gkr_pk_index_set_quarks (GkrPkObject *obj, const gchar *field, GQuark *quarks)
+gkr_pk_index_set_quarks (GkrPkIndex *index, gkrconstid digest, 
+                         const gchar *field, GQuark *quarks)
 {
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	GString *string;
+	gboolean ret;
+	gchar *value;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
 	g_return_val_if_fail (field != NULL, FALSE);
 
-	return update_pk_index_value (get_index_singleton (), obj->location, obj->digest, 
-	                              field, obj, (WriteValueFunc)write_quarks_value, &quarks);
+	/* Build up a string with all of this */
+	string = g_string_new (NULL);
+	while (*quarks) {
+		value = g_strescape (g_quark_to_string (*quarks), "");
+		if (string->len > 0)
+			g_string_append_c (string, '\n');
+		g_string_append (string, value);
+		g_free (value);
+		++quarks;
+	}
+
+	/* Store it as a string */
+	ret = write_string (index, digest, field, string->str);
+	g_string_free (string, TRUE);
+	return ret;
 }
 
 gboolean
-gkr_pk_index_delete (GkrPkObject *obj, const gchar *field)
+gkr_pk_index_clear (GkrPkIndex *index, gkrconstid digest, 
+                     const gchar *field)
 {
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	GkrKeyringItem *item;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
 	g_return_val_if_fail (field != NULL, FALSE);
 
-	return update_pk_index_value (get_index_singleton (), obj->location, obj->digest, 
-	                              field, obj, (WriteValueFunc)write_delete, NULL);
+	item = find_item_for_digest (index, digest, FALSE);
+	if (!item)
+		return FALSE;
+	
+	if (!gkr_attribute_list_find (item->attributes, field))
+		return FALSE;
+
+	gkr_attribute_list_delete (item->attributes, field);
+	if (!gkr_keyring_save_to_disk (index->keyring))
+		g_warning ("clearing field '%s': couldn't write index keyring to disk", field);
+	return TRUE;
+}
+
+gboolean
+gkr_pk_index_rename (GkrPkIndex *index, gkrconstid old_digest, gkrconstid new_digest)
+{
+	GnomeKeyringAttribute attr;
+	GkrKeyringItem *item;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+	g_return_val_if_fail (old_digest != NULL, FALSE);
+	g_return_val_if_fail (new_digest != NULL, FALSE);
+	
+	item = find_item_for_digest (index, old_digest, FALSE);
+	if (!item)
+		return FALSE;
+
+	if (gkr_id_equals (old_digest, new_digest))
+		return FALSE;
+	
+	attr.name = "object-digest";
+	attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+	attr.value.string = digest_to_group (new_digest);
 
+	gkr_attribute_list_set (item->attributes, &attr);
+	g_free (attr.value.string);
+	
+	if (!gkr_keyring_save_to_disk (index->keyring))
+		g_warning ("renaming item: couldn't write index keyring to disk");
+	return TRUE;
 }
 
 gboolean
-gkr_pk_index_clear (GkrPkObject *obj)
+gkr_pk_index_copy (GkrPkIndex *old_index, GkrPkIndex *new_index, gkrconstid digest)
 {
-	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	GkrKeyringItem *item;
+	
+	if (!old_index)
+		old_index = gkr_pk_index_default ();
+	if (!new_index)
+		new_index = gkr_pk_index_default ();
 
-	return update_pk_index_value (get_index_singleton (), obj->location, obj->digest, 
-	                              NULL, obj, (WriteValueFunc)write_clear, NULL);
+	g_return_val_if_fail (GKR_IS_PK_INDEX (old_index), FALSE);
+	g_return_val_if_fail (GKR_IS_PK_INDEX (new_index), FALSE);
+	g_return_val_if_fail (digest != NULL, FALSE);
 
+	if (old_index == new_index)
+		return FALSE;
+	
+	item = find_item_for_digest (old_index, digest, FALSE);
+	if (!item)
+		return FALSE;
+	
+	item = gkr_keyring_item_clone (new_index->keyring, item);
+	gkr_keyring_add_item (new_index->keyring, item);
+	
+	if (!gkr_keyring_save_to_disk (new_index->keyring))
+		g_warning ("copying item: couldn't write index keyring to disk");
+
+	return TRUE;
 }
 
 gboolean
+gkr_pk_index_delete (GkrPkIndex *index, gkrconstid digest)
+{
+	GkrKeyringItem *item;
+	
+	if (!index)
+		index = gkr_pk_index_default ();
+
+	g_return_val_if_fail (GKR_IS_PK_INDEX (index), FALSE);
+	
+	item = find_item_for_digest (index, digest, FALSE);
+	if (!item)
+		return FALSE;
+	
+	gkr_keyring_remove_item (index->keyring, item);
+	
+	if (!gkr_keyring_save_to_disk (index->keyring))
+		g_warning ("deleting item: couldn't write index keyring to disk");
+	
+	return TRUE;
+}
+
+/* ------------------------------------------------------------------------
+ * QUARK LISTS
+ */
+
+gboolean
 gkr_pk_index_quarks_has (GQuark *quarks, GQuark check)
 {
 	while (*quarks) {

Modified: trunk/pk/gkr-pk-index.h
==============================================================================
--- trunk/pk/gkr-pk-index.h	(original)
+++ trunk/pk/gkr-pk-index.h	Mon Jul  7 21:17:26 2008
@@ -24,56 +24,94 @@
 #ifndef GKRPKINDEX_H_
 #define GKRPKINDEX_H_
 
-
 #include <glib.h>
 
-#include "gkr-pk-object.h"
+#include "common/gkr-id.h"
+
+#include "keyrings/gkr-keyring.h"
+
+#include "library/gnome-keyring.h"
+
+#define GKR_TYPE_PK_INDEX             (gkr_pk_index_get_type())
+#define GKR_PK_INDEX(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), GKR_TYPE_PK_INDEX, GkrPkIndex))
+#define GKR_IS_PK_INDEX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), GKR_TYPE_PK_INDEX))
+
+typedef struct _GkrPkIndex      GkrPkIndex;
+typedef struct _GkrPkIndexClass GkrPkIndexClass;
+
+struct _GkrPkIndex {
+	 GObject parent;
+	 GkrKeyring *keyring;
+	 gboolean denied;
+	 GnomeKeyringAttributeList *defaults;
+};
+
+struct _GkrPkIndexClass {
+	GObjectClass parent_class;
+};
+
+GType               gkr_pk_index_get_type              (void);
+
+GkrPkIndex*         gkr_pk_index_new                   (GkrKeyring* keyring, 
+                                                        GnomeKeyringAttributeList *defaults);
 
-gboolean            gkr_pk_index_get_boolean           (GkrPkObject *object, const gchar *field, 
-                                                        gboolean defvalue);
+GkrPkIndex*         gkr_pk_index_open                  (GQuark index_location, const gchar *name, 
+                                                        GnomeKeyringAttributeList *defaults);
 
-gboolean            gkr_pk_index_get_boolean_full      (GQuark location, gkrconstid digest, 
+GkrPkIndex*         gkr_pk_index_default               (void);
+
+gboolean            gkr_pk_index_get_boolean           (GkrPkIndex *index, gkrconstid digest,
                                                         const gchar *field, gboolean defvalue);
 
-gint                gkr_pk_index_get_int               (GkrPkObject *object, const gchar *field, 
-                                                        gint defvalue);
+guint               gkr_pk_index_get_uint              (GkrPkIndex *index, gkrconstid digest, 
+                                                        const gchar *field, guint defvalue);
                                                                   
-gchar*              gkr_pk_index_get_string            (GkrPkObject *object, const gchar *field);
+gchar*              gkr_pk_index_get_string            (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field);
 
-gchar*              gkr_pk_index_get_string_full       (GQuark location, gkrconstid digest, const gchar *field);
+gchar*              gkr_pk_index_get_secret            (GkrPkIndex *index, gkrconstid digest);
 
-guchar*             gkr_pk_index_get_binary            (GkrPkObject *object, const gchar *field, 
-                                                        gsize *n_data);
+guchar*             gkr_pk_index_get_binary            (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field, gsize *n_data);
                                                         
-GQuark*             gkr_pk_index_get_quarks            (GkrPkObject *object, const gchar *field);
+GQuark*             gkr_pk_index_get_quarks            (GkrPkIndex *index, gkrconstid digest, 
+                                                        const gchar *field);
 
-gboolean            gkr_pk_index_set_boolean           (GkrPkObject *object, const gchar *field, 
-                                                        gboolean val);
+gboolean            gkr_pk_index_set_boolean           (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field, gboolean val);
 
-gboolean            gkr_pk_index_set_int               (GkrPkObject *object, const gchar *field, 
-                                                        gint val);
+gboolean            gkr_pk_index_set_uint              (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field, guint val);
                                                         
-gboolean            gkr_pk_index_set_string            (GkrPkObject *object, const gchar *field, 
-                                                        const gchar *val);
-                                         
-gboolean            gkr_pk_index_set_string_full       (GQuark location, gkrconstid digest, 
+gboolean            gkr_pk_index_set_string            (GkrPkIndex *index, gkrconstid digest,
                                                         const gchar *field, const gchar *val);
-                                                        
-gboolean            gkr_pk_index_set_binary            (GkrPkObject *object, const gchar *field, 
-                                                        const guchar *data, gsize n_data);
 
-gboolean            gkr_pk_index_set_quarks            (GkrPkObject *object, const gchar *field, 
-                                                        GQuark *quarks);
+gboolean            gkr_pk_index_set_secret            (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *secret);
 
-gboolean            gkr_pk_index_has_value             (GkrPkObject *object, const gchar *field);
-                                                        
-gboolean            gkr_pk_index_delete                (GkrPkObject *object, const gchar *field);
+gboolean            gkr_pk_index_set_binary            (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field, const guchar *data, 
+                                                        gsize n_data);
+
+gboolean            gkr_pk_index_set_quarks            (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field, GQuark *quarks);
+
+gboolean            gkr_pk_index_has_value             (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field);
+
+gboolean            gkr_pk_index_clear                 (GkrPkIndex *index, gkrconstid digest,
+                                                        const gchar *field);
+
+gboolean            gkr_pk_index_rename                (GkrPkIndex *index, gkrconstid old_digest, 
+                                                        gkrconstid new_digest);
+
+gboolean            gkr_pk_index_copy                  (GkrPkIndex *old_index, GkrPkIndex *new_index,
+                                                        gkrconstid digest);
 
-gboolean            gkr_pk_index_have                  (GkrPkObject *object);
+gboolean            gkr_pk_index_delete                (GkrPkIndex *index, gkrconstid digest);
 
-gboolean            gkr_pk_index_have_full             (GQuark location, gkrconstid digest);
+gboolean            gkr_pk_index_have                  (GkrPkIndex *index, gkrconstid digest);
 
-gboolean            gkr_pk_index_clear                 (GkrPkObject *object);
 
 /* -----------------------------------------------------------------------------
  * LISTS OF QUARKS

Modified: trunk/pk/gkr-pk-object-manager.c
==============================================================================
--- trunk/pk/gkr-pk-object-manager.c	(original)
+++ trunk/pk/gkr-pk-object-manager.c	Mon Jul  7 21:17:26 2008
@@ -25,8 +25,8 @@
 
 #include "gkr-pk-cert.h"
 #include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
 #include "gkr-pk-privkey.h"
+#include "gkr-pk-storage.h"
 #include "gkr-pk-util.h"
 
 #include "common/gkr-cleanup.h"
@@ -411,7 +411,7 @@
 	}
 
 	if (do_refresh) 
-		gkr_pk_object_storage_refresh (NULL);
+		gkr_pk_storage_refresh_all ();
 
 	/* TODO: We may want to only go through objects of CKA_CLASS */
 	for (l = man->objects; l; l = g_list_next (l)) {

Modified: trunk/pk/gkr-pk-object-storage.c
==============================================================================
--- trunk/pk/gkr-pk-object-storage.c	(original)
+++ trunk/pk/gkr-pk-object-storage.c	Mon Jul  7 21:17:26 2008
@@ -174,9 +174,10 @@
 	}
 }
 
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 static gchar* 
 parser_ask_password (GkrPkixParser *parser, GQuark loc, gkrid digest, 
-                     GQuark type, const gchar *label, guint failures,
+                     GQuark type, const gchar *label, gint *state,
                      ParseContext *ctx)
 {
  	GkrPkObjectStoragePrivate *pv = GKR_PK_OBJECT_STORAGE_GET_PRIVATE (ctx->storage);
@@ -292,9 +293,11 @@
 			                                 "pk-object", gkr_location_to_string (loc), NULL);
 		} 
 		
+	xxxxxxxxxxxxxxxxxxxxxx
 		/* Track that we prompted for this */
 		g_hash_table_insert (ctx->types_by_digest, gkr_id_dup (digest), 
 		                     GUINT_TO_POINTER (type));
+	xxxxxxxxxxxxxxxxxxxxxx
 	}	
 		
 	g_free (custom_label);
@@ -593,6 +596,7 @@
 	g_signal_connect (parser, "parsed-asn1", G_CALLBACK (parser_parsed_asn1), &ctx);
 	g_signal_connect (parser, "parsed-sexp", G_CALLBACK (parser_parsed_sexp), &ctx);
 	g_signal_connect (parser, "parsed-partial", G_CALLBACK (parser_parsed_partial), &ctx);
+	xxxxxxxxxxxxxxxxxxxxxxxx
  	g_signal_connect (parser, "ask-password", G_CALLBACK (parser_ask_password), &ctx);
 
 	ret = gkr_pkix_parser_parse_location (parser, loc, err);

Modified: trunk/pk/gkr-pk-object-storage.h
==============================================================================
--- trunk/pk/gkr-pk-object-storage.h	(original)
+++ trunk/pk/gkr-pk-object-storage.h	Mon Jul  7 21:17:26 2008
@@ -33,11 +33,12 @@
 
 #define GKR_TYPE_PK_OBJECT_STORAGE             (gkr_pk_object_storage_get_type ())
 #define GKR_PK_OBJECT_STORAGE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_OBJECT_STORAGE, GkrPkObjectStorage))
-#define GKR_PK_OBJECT_STORAGE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_OBJECT_STORAGE, GObject))
+#define GKR_PK_OBJECT_STORAGE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_OBJECT_STORAGE, GkrPkObjectStorageClass))
 #define GKR_IS_PK_OBJECT_STORAGE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_OBJECT_STORAGE))
 #define GKR_IS_PK_OBJECT_STORAGE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_OBJECT_STORAGE))
 #define GKR_PK_OBJECT_STORAGE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_OBJECT_STORAGE, GkrPkObjectStorageClass))
 
+typedef struct _GkrPkObjectStorage GkrPkObjectStorage;
 typedef struct _GkrPkObjectStorageClass GkrPkObjectStorageClass;
 
 struct _GkrPkObjectStorage {

Modified: trunk/pk/gkr-pk-object.c
==============================================================================
--- trunk/pk/gkr-pk-object.c	(original)
+++ trunk/pk/gkr-pk-object.c	Mon Jul  7 21:17:26 2008
@@ -29,6 +29,7 @@
 #include "gkr-pk-object-manager.h"
 #include "gkr-pk-privkey.h"
 #include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
 #include "gkr-pk-util.h"
 
 #include "common/gkr-location.h"
@@ -45,7 +46,8 @@
 	PROP_LOCATION,
 	PROP_DIGEST,
 	PROP_ORIG_LABEL,
-	PROP_LABEL
+	PROP_LABEL,
+	PROP_STORAGE
 };
 
 enum {
@@ -59,6 +61,7 @@
 	GHashTable *attr_cache;
 	gchar *orig_label;
 	guint load_state;
+	gboolean dummy_digest;
 	
 	gchar *data_path;
 	gchar *data_section;
@@ -108,6 +111,42 @@
 	return CKR_OK;
 }
 
+static void
+move_indexes_if_necessary (GkrPkObject *obj, GkrPkStorage *copy_storage, 
+                           GQuark copy_location)
+{
+	GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (obj);
+	GkrPkIndex *old_index = NULL;
+	GkrPkIndex *new_index = NULL;
+	
+	if (obj->storage)
+		old_index = gkr_pk_storage_index (obj->storage, obj->location);
+	if (copy_storage)
+		new_index = gkr_pk_storage_index (copy_storage, copy_location);
+	
+	if (old_index == new_index)
+		return;
+	
+	gkr_pk_index_copy (old_index, new_index, obj->digest);
+	
+	/* 
+	 * If the index is a dummy index, or wasn't being stored 
+	 * somewhere 'real', then remove the old indexes too.
+	 */
+	if (pv->dummy_digest || !obj->storage)
+		gkr_pk_index_delete (old_index, obj->digest);
+}
+
+static void
+remove_indexes (GkrPkObject *obj)
+{
+	GkrPkIndex *index = NULL;
+	
+	if (obj->storage)
+		index = gkr_pk_storage_index (obj->storage, obj->location);
+	gkr_pk_index_delete (index, obj->digest);
+}
+
 /* --------------------------------------------------------------------------------
  * OBJECT
  */
@@ -118,6 +157,10 @@
 	GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (obj);
 	pv->attr_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, 
 	                                        NULL, gkr_pk_attribute_free);
+	
+	/* Create a dummy digest which is the object address */
+	pv->dummy_digest = TRUE;
+	obj->digest = gkr_id_new ((guchar*)&obj, sizeof (obj));
 }
 
 static GObject*
@@ -134,15 +177,21 @@
 		
 	xobj = GKR_PK_OBJECT (obj);
 	
-	/* Find the object manager and register */
-	for (i = 0; i < n_props; ++i) {
-		if (props[i].pspec->name && g_str_equal (props[i].pspec->name, "manager")) {
-			mgr = g_value_get_object (props[i].value);
-			if (mgr) {
-				gkr_pk_object_manager_register (mgr, xobj);
-				g_return_val_if_fail (xobj->manager == mgr, obj);
+	/* 
+	 * Find the object manager and register, if we have 
+	 * a digest setup already. Otherwise this'll happen
+	 * later (see PROP_DIGEST in gkr_pk_object_set_property)
+	  */
+	if (xobj->digest) {
+		for (i = 0; i < n_props; ++i) {
+			if (props[i].pspec->name && g_str_equal (props[i].pspec->name, "manager")) {
+				mgr = g_value_get_object (props[i].value);
+				if (mgr) {
+					gkr_pk_object_manager_register (mgr, xobj);
+					g_return_val_if_fail (xobj->manager == mgr, obj);
+				}
+				break;
 			}
-			break;
 		}
 	}
 	
@@ -247,6 +296,9 @@
 	case PROP_LABEL:
 		g_value_take_string (value, gkr_pk_object_get_label (xobj));
 		break;
+	case PROP_STORAGE:
+		g_value_set_object (value, xobj->storage);
+		break;
 	}
 }
 
@@ -256,6 +308,10 @@
 {
 	GkrPkObject *xobj = GKR_PK_OBJECT (obj);
 	GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (xobj);
+	GkrPkIndex *index;
+	GkrPkStorage *storage;
+	gkrid digest;
+	GQuark location;
 	
 	switch (prop_id) {
 	case PROP_MANAGER:
@@ -265,28 +321,80 @@
 		 * taken effect. See above.
 		 */
 		break; 
+		
 	case PROP_LOCATION:
-		xobj->location = g_value_get_uint (value);
+		location = g_value_get_uint (value);
+		if (location)
+			move_indexes_if_necessary (xobj, xobj->storage, location);
+		xobj->location = location; 
 		break;
+		
 	case PROP_DIGEST:
+		/* 
+		 * This is a bit of complicated song and dance. The digest uniquely
+		 * identifies the object in many cases. When it changes, all sorts 
+		 * of stuff needs to change.
+		 */
+		
+		g_return_if_fail (xobj->digest);
+		digest = gkr_id_dup (g_value_get_boxed (value));
+		g_return_if_fail (digest);
+		
+		/* Unregister old digest with object manager */
+		if (xobj->manager)
+			gkr_pk_object_manager_unregister (xobj->manager, xobj);
+
+		/* Rename to the new digest in the index */
+		index = xobj->storage ? gkr_pk_storage_index (xobj->storage, xobj->location) : NULL;
+		if (gkr_pk_index_have (index, xobj->digest)) {
+			if (!gkr_pk_index_rename (index, xobj->digest, digest))
+				g_return_if_reached ();
+		}
+
+		/* Change to new digest */
 		gkr_id_free (xobj->digest);
-		xobj->digest = gkr_id_dup (g_value_get_boxed (value));
+		xobj->digest = digest;
+
+		/* Register with the object manager with the new digest */
+		if (xobj->manager)
+			gkr_pk_object_manager_register (xobj->manager, xobj);
+		
 		break;
+		
 	case PROP_ORIG_LABEL:
 		g_free (pv->orig_label);
 		pv->orig_label = g_value_dup_string (value);
 		break;
+		
 	case PROP_LABEL:
 		gkr_pk_object_set_label (xobj, g_value_get_string (value));
 		break;
-	}
+		
+	case PROP_STORAGE:
+		/* 
+		 * We're changing storages at this point. We may get a new index
+		 * so try to move everything from the old index to the new. 
+		 */
+		storage = g_value_get_object (value);
+		if (storage)
+			move_indexes_if_necessary (xobj, storage, xobj->location);
+		
+		/* We don't reference, storage should remove itself before the end */
+		xobj->storage = storage;
+		break;
+	};
 }
                                     
 static void
 gkr_pk_object_finalize (GObject *obj)
 {
 	GkrPkObject *xobj = GKR_PK_OBJECT (obj);
-	GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (xobj);	
+	GkrPkObjectPrivate *pv = GKR_PK_OBJECT_GET_PRIVATE (xobj);
+	
+	/* If this never actually got stored properly, then remove it */
+	if (pv->dummy_digest || !xobj->storage)
+		remove_indexes (xobj);
+	
 	if (pv->attr_cache)
 		g_hash_table_destroy (pv->attr_cache);
 		
@@ -297,6 +405,9 @@
 	if (xobj->manager)
 		gkr_pk_object_manager_unregister (xobj->manager, xobj);
 	g_return_if_fail (xobj->manager == NULL);
+	
+	gkr_id_free (xobj->digest);
+	xobj->digest = NULL;
 
 	G_OBJECT_CLASS (gkr_pk_object_parent_class)->finalize (obj);
 }
@@ -333,11 +444,15 @@
 		                    
 	g_object_class_install_property (gobject_class, PROP_ORIG_LABEL,
 		g_param_spec_string ("orig-label", "Original Label", "Original Label",
-		                     NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		                     NULL, G_PARAM_READWRITE));
 		                     
 	g_object_class_install_property (gobject_class, PROP_LABEL,
 		g_param_spec_string ("label", "Label", "PK Object Label",
 		                     NULL, G_PARAM_READWRITE));
+	
+	g_object_class_install_property (gobject_class, PROP_STORAGE,
+		g_param_spec_object ("storage", "Storage", "Storage for this Object",
+		                     GKR_TYPE_PK_STORAGE, G_PARAM_READWRITE));
 }
 
 /* --------------------------------------------------------------------------------
@@ -430,7 +545,7 @@
 		ret = (*klass->import) (object);
 	
 	if (ret)
-		gkr_pk_index_set_boolean (object, "imported", TRUE);
+		gkr_pk_object_index_set_boolean (object, "imported", TRUE);
 	
 	return ret;
 }
@@ -670,15 +785,168 @@
 gkr_pk_object_get_label (GkrPkObject *xobj)
 {
 	g_return_val_if_fail (GKR_IS_PK_OBJECT (xobj), NULL);
-	return gkr_pk_index_get_string (xobj, "label");
+	return gkr_pk_object_index_get_string (xobj, "label");
 }
 
 void
 gkr_pk_object_set_label (GkrPkObject *xobj, const gchar *label)
 {
 	g_return_if_fail (GKR_IS_PK_OBJECT (xobj));
-	if (!label)
-		gkr_pk_index_delete (xobj, "label");
-	else
-		gkr_pk_index_set_string (xobj, "label", label);
+	gkr_pk_object_index_set_string (xobj, "label", label);
+}
+
+/* -------------------------------------------------------------------
+ * INDEX HELPERS 
+ */
+
+gboolean
+gkr_pk_object_index_has_value (GkrPkObject *object, const gchar *field)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (object), FALSE);
+	g_return_val_if_fail (object->digest, FALSE);
+	g_return_val_if_fail (field, FALSE);
+
+	if (object->storage) {
+		g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_val_if_fail (index, FALSE);
+	} 
+	
+	return gkr_pk_index_has_value (index, object->digest, field);
+}
+
+GQuark*
+gkr_pk_object_index_get_quarks (GkrPkObject *object, const gchar *field)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (object), NULL);
+	g_return_val_if_fail (object->digest, NULL);
+	g_return_val_if_fail (field, NULL);
+	
+	if (object->storage) {
+		g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_val_if_fail (index, FALSE);
+	} 
+	
+	return gkr_pk_index_get_quarks (index, object->digest, field);
+}
+
+gchar*
+gkr_pk_object_index_get_string (GkrPkObject *object, const gchar *field)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (object), NULL);
+	g_return_val_if_fail (object->digest, NULL);
+	g_return_val_if_fail (field, NULL);
+	
+	if (object->storage) {
+		g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_val_if_fail (index, FALSE);
+	} 
+	
+	return gkr_pk_index_get_string (index, object->digest, field);
+}
+
+guchar*
+gkr_pk_object_index_get_binary (GkrPkObject *object, const gchar *field,
+                                gsize *n_data)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (object), NULL);
+	g_return_val_if_fail (object->digest, NULL);
+	g_return_val_if_fail (field, NULL);
+	
+	if (object->storage) {
+		g_return_val_if_fail (GKR_IS_PK_STORAGE (object->storage), FALSE);
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_val_if_fail (index, FALSE);
+	} 
+	
+	return gkr_pk_index_get_binary (index, object->digest, field, n_data);
+}
+
+void
+gkr_pk_object_index_set_boolean (GkrPkObject *object, const gchar *field,
+                                 gboolean value)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (object->digest);
+	g_return_if_fail (field);
+	
+	if (object->storage) {
+		g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_if_fail (index);
+	} 
+	
+	if (gkr_pk_index_set_boolean (index, object->digest, field, value))
+		gkr_pk_object_flush (object);
+}
+
+void
+gkr_pk_object_index_set_string (GkrPkObject *object, const gchar *field,
+                                const gchar *string)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (object->digest);
+	g_return_if_fail (field);
+	
+	if (object->storage) {
+		g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_if_fail (index);
+	} 
+	
+	if (gkr_pk_index_set_string (index, object->digest, field, string))
+		gkr_pk_object_flush (object);
+}
+
+void
+gkr_pk_object_index_set_binary (GkrPkObject *object, const gchar *field,
+                                const guchar *data, gsize n_data)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (object->digest);
+	g_return_if_fail (field);
+
+	if (object->storage) {
+		g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_if_fail (index);
+	}
+	
+	if (gkr_pk_index_set_binary (index, object->digest, field, data, n_data))
+		gkr_pk_object_flush (object);
+}
+
+void
+gkr_pk_object_index_clear (GkrPkObject *object, const gchar *field)
+{
+	GkrPkIndex *index = NULL;
+	
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (object->digest);
+	g_return_if_fail (field);
+
+	if (object->storage) {
+		g_return_if_fail (GKR_IS_PK_STORAGE (object->storage));
+		index = gkr_pk_storage_index (object->storage, object->location);
+		g_return_if_fail (index);
+	}
+	
+	if (gkr_pk_index_clear (index, object->digest, field))
+		gkr_pk_object_flush (object);
 }

Modified: trunk/pk/gkr-pk-object.h
==============================================================================
--- trunk/pk/gkr-pk-object.h	(original)
+++ trunk/pk/gkr-pk-object.h	Mon Jul  7 21:17:26 2008
@@ -45,7 +45,7 @@
 typedef struct _GkrPkObject      GkrPkObject;
 typedef struct _GkrPkObjectClass GkrPkObjectClass;
 
-typedef struct _GkrPkObjectStorage GkrPkObjectStorage;
+typedef struct _GkrPkStorage GkrPkStorage;
 typedef struct _GkrPkObjectManager GkrPkObjectManager;
 
 struct _GkrPkObject {
@@ -56,7 +56,7 @@
 	CK_OBJECT_HANDLE handle;
 	
 	GkrPkObjectManager *manager;
-	GkrPkObjectStorage *storage;
+	GkrPkStorage *storage;
 };
 
 struct _GkrPkObjectClass {
@@ -150,6 +150,39 @@
 void                gkr_pk_object_set_label        (GkrPkObject *object, 
                                                     const gchar *label);
 
+/* -------------------------------------------------------------------
+ * Helpers to access the index for an object 
+ */
+
+gboolean            gkr_pk_object_index_has_value    (GkrPkObject *object,
+                                                      const gchar *field);
+
+GQuark*             gkr_pk_object_index_get_quarks   (GkrPkObject *object,
+                                                      const gchar *field);
+
+gchar*              gkr_pk_object_index_get_string   (GkrPkObject *object,
+                                                      const gchar *field);
+
+guchar*             gkr_pk_object_index_get_binary   (GkrPkObject *object,
+                                                      const gchar *field,
+                                                      gsize *n_data);
+
+void                gkr_pk_object_index_set_boolean  (GkrPkObject *object,
+                                                      const gchar *field,
+                                                      gboolean value);
+
+void                gkr_pk_object_index_set_string   (GkrPkObject *object,
+                                                      const gchar *field,
+                                                      const gchar *string);
+
+void                gkr_pk_object_index_set_binary   (GkrPkObject *object,
+                                                      const gchar *field,
+                                                      const guchar *data,
+                                                      gsize n_data);
+
+void                gkr_pk_object_index_clear        (GkrPkObject *object, 
+                                                      const gchar *field);
+
 G_END_DECLS
 
 #endif /* __GKR_PK_OBJECT_H__ */

Modified: trunk/pk/gkr-pk-privkey.c
==============================================================================
--- trunk/pk/gkr-pk-privkey.c	(original)
+++ trunk/pk/gkr-pk-privkey.c	Mon Jul  7 21:17:26 2008
@@ -27,9 +27,9 @@
 #include "gkr-pk-index.h"
 #include "gkr-pk-object.h"
 #include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
 #include "gkr-pk-privkey.h"
 #include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
 #include "gkr-pk-util.h"
 
 #include "common/gkr-crypto.h"
@@ -86,7 +86,7 @@
 	obj = GKR_PK_OBJECT (key);
 	
 	g_return_val_if_fail (obj->storage, CKR_GENERAL_ERROR);
-	if (!gkr_pk_object_storage_load_complete (obj->storage, obj, &err)) {
+	if (!gkr_pk_storage_load (obj->storage, obj, &err)) {
 		g_message ("couldn't load private key for: %s: %s", 
 		           g_quark_to_string (obj->location),
 		           err && err->message ? err->message : "");
@@ -116,7 +116,7 @@
 	obj = GKR_PK_OBJECT (key);
 	
 	/* Do we have a public key in the indexes? */
-	data = gkr_pk_index_get_binary (obj, "public-key", &n_data);
+	data = gkr_pk_object_index_get_binary (obj, "public-key", &n_data);
 	if (data) {
 		res = gkr_pkix_der_read_public_key (data, n_data, &s_key);
 		if (res == GKR_PKIX_SUCCESS) {
@@ -125,7 +125,7 @@
 			goto done;
 		} 
 
-		gkr_pk_index_delete (obj, "public-key");	
+		gkr_pk_object_index_set_binary (obj, "public-key", NULL, 0);
 		g_warning ("invalid public-key in indexes for: %s", g_quark_to_string (obj->location));
 	}
 	
@@ -147,8 +147,7 @@
 		g_return_val_if_fail (data != NULL, NULL);
 		
 		/* Write the public key out to the indexes */
-		if (!gkr_pk_index_set_binary (obj, "public-key", data, n_data))
-			g_warning ("couldn't write public key to index for: %s", g_quark_to_string (obj->location));
+		gkr_pk_object_index_set_binary (obj, "public-key", data, n_data);
 		
 		key->priv->pubkey = gkr_pk_pubkey_instance (obj->manager, 0, s_key);
 		goto done;
@@ -414,7 +413,7 @@
 		return CKR_OK;
 
 	case CKA_GNOME_PURPOSE_SSH_AUTH:
-		quarks = gkr_pk_index_get_quarks (obj, "purposes");
+		quarks = gkr_pk_object_index_get_quarks (obj, "purposes");
 		gkr_pk_attribute_set_boolean (attr, quarks && 
 				gkr_pk_index_quarks_has (quarks, SSH_AUTHENTICATION));
 		gkr_pk_index_quarks_free (quarks);

Modified: trunk/pk/gkr-pk-pubkey.c
==============================================================================
--- trunk/pk/gkr-pk-pubkey.c	(original)
+++ trunk/pk/gkr-pk-pubkey.c	Mon Jul  7 21:17:26 2008
@@ -27,8 +27,8 @@
 #include "gkr-pk-index.h"
 #include "gkr-pk-object.h"
 #include "gkr-pk-object-manager.h"
-#include "gkr-pk-object-storage.h"
 #include "gkr-pk-pubkey.h"
+#include "gkr-pk-storage.h"
 #include "gkr-pk-util.h"
 
 #include "common/gkr-crypto.h"
@@ -113,7 +113,7 @@
 		
 	obj = GKR_PK_OBJECT (key);
 	
-	if (!gkr_pk_object_storage_load_complete (obj->storage, obj, &err)) {
+	if (!gkr_pk_storage_load (obj->storage, obj, &err)) {
 		g_message ("couldn't load public key for: %s: %s", 
 		           g_quark_to_string (obj->location),
 		           err && err->message ? err->message : "");

Added: trunk/pk/gkr-pk-root-storage.c
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-root-storage.c	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,280 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-root-storage.c - Storage of Trusted Root CAs
+
+   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 "gkr-pk-cert.h"
+#include "gkr-pk-object-manager.h"
+#include "gkr-pk-root-storage.h"
+#include "gkr-pk-util.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-location.h"
+#include "common/gkr-location-watch.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "pkix/gkr-pkix-asn1.h"
+#include "pkix/gkr-pkix-der.h"
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+typedef struct _GkrPkRootStoragePrivate GkrPkRootStoragePrivate;
+
+struct _GkrPkRootStoragePrivate {
+	gkrid specific_load_request;
+	GkrLocationWatch *watch;
+};
+
+#define GKR_PK_ROOT_STORAGE_GET_PRIVATE(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GKR_TYPE_PK_ROOT_STORAGE, GkrPkRootStoragePrivate))
+
+G_DEFINE_TYPE(GkrPkRootStorage, gkr_pk_root_storage, GKR_TYPE_PK_STORAGE);
+
+typedef struct {
+	GkrPkRootStorage *storage;         /* The object storage to parse into */
+	GHashTable *checks;                /* The set of objects that existed before parse */
+} ParseContext;
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static GkrPkObject*
+prepare_object (GkrPkRootStorage *storage, GQuark location, gkrconstid digest)
+{
+	GkrPkObjectManager *manager;
+	GkrPkObject *object;
+	
+	manager = gkr_pk_object_manager_for_token ();
+	object = gkr_pk_object_manager_find_by_digest (manager, digest);
+	
+	/* The object already exists just reference it */
+	if (object) {
+		gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+		return object;
+	} 
+	
+	object = g_object_new (GKR_TYPE_PK_CERT, "manager", manager, "location", location, 
+	                       "digest", digest, NULL);
+	gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+
+	/* Object was reffed */
+	g_object_unref (object);
+	return object;
+}
+
+static gboolean
+parser_parsed_asn1 (GkrPkixParser *parser, GQuark location, gkrconstid digest, 
+                    GQuark type, ASN1_TYPE asn1, ParseContext *ctx)
+{
+ 	GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (ctx->storage);
+	GkrPkObject *object;
+	
+ 	g_return_val_if_fail (type != 0, FALSE);
+ 	
+ 	/* We only handle certificates */
+ 	if (type == GKR_PKIX_CERTIFICATE)
+ 		return FALSE;
+ 	
+	object = prepare_object (ctx->storage, location, digest);
+	g_return_val_if_fail (object != NULL, FALSE);
+
+	/* Make note of having seen this object in load requests */
+	if (gkr_id_equals (pv->specific_load_request, digest))
+		pv->specific_load_request = NULL;
+	
+	/* Make note of having seen this one */
+	gkr_pk_storage_checks_mark (ctx->checks, object);
+	
+	/* Setup the asn1, probably a certificate on this object */
+	g_object_set (object, "asn1-tree", asn1, NULL); 
+	
+	return TRUE;
+}
+
+static gboolean
+storage_load_certificate (GkrPkRootStorage *storage, GQuark loc, GError **err)
+{
+ 	GkrPkixParser *parser;
+ 	GkrPkixResult ret;
+	ParseContext ctx;
+	
+	g_return_val_if_fail (loc != 0, FALSE);
+
+	ctx.storage = storage;
+
+	/* Create a table of what is at the location */
+	ctx.checks = gkr_pk_storage_checks_prepare (GKR_PK_STORAGE (storage), loc);
+
+	/* TODO: Try and use a shared parser? */
+	parser = gkr_pkix_parser_new ();
+	g_signal_connect (parser, "parsed-asn1", G_CALLBACK (parser_parsed_asn1), &ctx);
+	ret = gkr_pkix_parser_parse_location (parser, loc, err);
+	g_object_unref (parser);
+
+	/* Remove any still in checks array */
+	gkr_pk_storage_checks_purge (GKR_PK_STORAGE (storage), ctx.checks);
+	
+	return ret;
+}
+
+static void
+location_load (GkrLocationWatch *watch, GQuark loc, GkrPkRootStorage *storage)
+{
+	GError *err = NULL;
+
+	/* We only get notified for private keys */
+	if (!storage_load_certificate (storage, loc, &err)) {
+		g_message ("couldn't load certificate data: %s: %s", g_quark_to_string (loc),
+		           err && err->message ? err->message : "");
+		g_error_free (err);
+	}
+}
+
+static void
+location_remove (GkrLocationWatch *watch, GQuark loc, GkrPkRootStorage *storage)
+{
+ 	gkr_pk_storage_clr_objects (GKR_PK_STORAGE (storage), loc);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void 
+gkr_pk_root_storage_refresh (GkrPkStorage *storage)
+{
+ 	GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (storage);
+ 	gkr_location_watch_refresh (pv->watch, FALSE);
+}
+
+static gboolean 
+gkr_pk_root_storage_load (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+	GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (storage);
+	gboolean ret = TRUE;
+		
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	g_return_val_if_fail (obj->storage == storage, FALSE);
+	g_return_val_if_fail (obj->location, FALSE);
+	g_return_val_if_fail (pv->specific_load_request == NULL, FALSE);
+
+	g_object_ref (obj);
+	
+	/* Make note of the specific load request */
+	pv->specific_load_request = obj->digest;
+	
+	/* Perform the actual load */
+	location_load (pv->watch, obj->location, GKR_PK_ROOT_STORAGE (storage));
+	
+	/* See if it was seen */
+	if (pv->specific_load_request != NULL) {
+		g_set_error (err, GKR_PKIX_PARSE_ERROR, 0, "The object was not found at: %s",
+		             g_quark_to_string (obj->location));
+		pv->specific_load_request = NULL;
+		ret = FALSE;
+	}
+		
+	g_object_unref (obj);
+	return ret;
+}
+
+static void
+gkr_pk_root_storage_init (GkrPkRootStorage *storage)
+{
+ 	GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (storage);
+ 	
+	pv->specific_load_request = NULL;
+	
+	/* The root certificates directory, mark as trusted anchors */
+	pv->watch = gkr_location_watch_new (NULL, GKR_LOCATION_VOLUME_FILE, ROOT_CERTIFICATES, "*", "*.0");
+	g_return_if_fail (pv->watch); 
+
+	g_signal_connect (pv->watch, "location-added", G_CALLBACK (location_load), storage);
+	g_signal_connect (pv->watch, "location-changed", G_CALLBACK (location_load), storage);
+	g_signal_connect (pv->watch, "location-removed", G_CALLBACK (location_remove), storage);
+}
+
+static void
+gkr_pk_root_storage_dispose (GObject *obj)
+{
+	GkrPkRootStorage *storage = GKR_PK_ROOT_STORAGE (obj);
+ 	GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (obj);
+ 	
+	g_signal_handlers_disconnect_by_func (pv->watch, location_load, storage);
+	g_signal_handlers_disconnect_by_func (pv->watch, location_remove, storage);
+ 	
+	G_OBJECT_CLASS (gkr_pk_root_storage_parent_class)->dispose (obj);
+}
+
+static void
+gkr_pk_root_storage_finalize (GObject *obj)
+{
+ 	GkrPkRootStoragePrivate *pv = GKR_PK_ROOT_STORAGE_GET_PRIVATE (obj);
+ 	
+	g_object_unref (pv->watch);
+ 	pv->watch = NULL;
+	
+	G_OBJECT_CLASS (gkr_pk_root_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_pk_root_storage_class_init (GkrPkRootStorageClass *klass)
+{
+	GkrPkStorageClass *storage_class = GKR_PK_STORAGE_CLASS (klass);
+	GObjectClass *gobject_class;
+	
+	gobject_class = (GObjectClass*)klass;
+	gobject_class->dispose = gkr_pk_root_storage_dispose;
+	gobject_class->finalize = gkr_pk_root_storage_finalize;
+
+	storage_class->refresh = gkr_pk_root_storage_refresh;
+	storage_class->load = gkr_pk_root_storage_load;
+	
+	gkr_pk_root_storage_parent_class = g_type_class_peek_parent (klass);
+
+	g_type_class_add_private (gobject_class, sizeof (GkrPkRootStoragePrivate));
+}
+
+/* -------------------------------------------------------------------------------
+ * PUBLIC FUNCTIONS
+ */
+
+GkrPkRootStorage*
+gkr_pk_root_storage_new (void)
+{
+	return g_object_new (GKR_TYPE_PK_ROOT_STORAGE, NULL);
+}

Added: trunk/pk/gkr-pk-root-storage.h
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-root-storage.h	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,36 @@
+#ifndef __GKR_PK_ROOT_STORAGE_H__
+#define __GKR_PK_ROOT_STORAGE_H__
+
+#include <glib-object.h>
+
+#include "pk/gkr-pk-storage.h"
+
+#include "pkix/gkr-pkix-types.h"
+
+G_BEGIN_DECLS
+
+#define GKR_TYPE_PK_ROOT_STORAGE             (gkr_pk_root_storage_get_type ())
+#define GKR_PK_ROOT_STORAGE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_ROOT_STORAGE, GkrPkRootStorage))
+#define GKR_PK_ROOT_STORAGE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_ROOT_STORAGE, GObject))
+#define GKR_IS_PK_ROOT_STORAGE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_ROOT_STORAGE))
+#define GKR_IS_PK_ROOT_STORAGE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_ROOT_STORAGE))
+#define GKR_PK_ROOT_STORAGE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_ROOT_STORAGE, GkrPkRootStorageClass))
+
+typedef struct _GkrPkRootStorage GkrPkRootStorage;
+typedef struct _GkrPkRootStorageClass GkrPkRootStorageClass;
+
+struct _GkrPkRootStorage {
+	 GkrPkStorage parent;
+};
+
+struct _GkrPkRootStorageClass {
+	GkrPkStorageClass parent_class;
+};
+
+GType                   gkr_pk_root_storage_get_type          (void) G_GNUC_CONST;
+
+GkrPkRootStorage*       gkr_pk_root_storage_new               (void);
+
+G_END_DECLS
+
+#endif /* __GKR_PK_ROOT_STORAGE_H__ */

Added: trunk/pk/gkr-pk-session-storage.c
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-session-storage.c	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,108 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-session-storage.c - Storage of session or temporary objects
+
+   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 "gkr-pk-cert.h"
+#include "gkr-pk-object-manager.h"
+#include "gkr-pk-session-storage.h"
+#include "gkr-pk-util.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-location.h"
+#include "common/gkr-location-watch.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "pkix/gkr-pkix-asn1.h"
+#include "pkix/gkr-pkix-der.h"
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+G_DEFINE_TYPE(GkrPkSessionStorage, gkr_pk_session_storage, GKR_TYPE_PK_STORAGE);
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkr_pk_session_storage_init (GkrPkSessionStorage *storage)
+{
+	GkrKeyring *keyring = gkr_keyring_new ("pk-session", 0);
+	storage->index = gkr_pk_index_new (keyring, NULL);
+	g_object_unref (keyring);
+}
+
+static GkrPkIndex*
+gkr_pk_session_storage_index (GkrPkStorage *storage, GQuark location)
+{
+	return GKR_PK_SESSION_STORAGE (storage)->index;
+}
+
+static void
+gkr_pk_session_storage_finalize (GObject *obj)
+{
+ 	GkrPkSessionStorage *storage = GKR_PK_SESSION_STORAGE (obj);
+
+ 	if (storage->index)
+ 		g_object_unref (storage->index);
+ 	storage->index = NULL;
+	
+	G_OBJECT_CLASS (gkr_pk_session_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_pk_session_storage_class_init (GkrPkSessionStorageClass *klass)
+{
+	GkrPkStorageClass *storage_class = GKR_PK_STORAGE_CLASS (klass);
+	GObjectClass *gobject_class;
+	
+	gobject_class = (GObjectClass*)klass;
+	gobject_class->finalize = gkr_pk_session_storage_finalize;
+
+	storage_class->index = gkr_pk_session_storage_index;
+	
+	gkr_pk_session_storage_parent_class = g_type_class_peek_parent (klass);
+}
+
+/* -------------------------------------------------------------------------------
+ * PUBLIC FUNCTIONS
+ */
+
+GkrPkSessionStorage*
+gkr_pk_session_storage_new (void)
+{
+	return g_object_new (GKR_TYPE_PK_SESSION_STORAGE, NULL);
+}

Added: trunk/pk/gkr-pk-session-storage.h
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-session-storage.h	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,35 @@
+#ifndef __GKR_PK_SESSION_STORAGE_H__
+#define __GKR_PK_SESSION_STORAGE_H__
+
+#include <glib-object.h>
+
+#include "pk/gkr-pk-storage.h"
+
+G_BEGIN_DECLS
+
+#define GKR_TYPE_PK_SESSION_STORAGE             (gkr_pk_session_storage_get_type ())
+#define GKR_PK_SESSION_STORAGE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_SESSION_STORAGE, GkrPkSessionStorage))
+#define GKR_PK_SESSION_STORAGE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_SESSION_STORAGE, GObject))
+#define GKR_IS_PK_SESSION_STORAGE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_SESSION_STORAGE))
+#define GKR_IS_PK_SESSION_STORAGE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_SESSION_STORAGE))
+#define GKR_PK_SESSION_STORAGE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_SESSION_STORAGE, GkrPkSessionStorageClass))
+
+typedef struct _GkrPkSessionStorage GkrPkSessionStorage;
+typedef struct _GkrPkSessionStorageClass GkrPkSessionStorageClass;
+
+struct _GkrPkSessionStorage {
+	 GkrPkStorage parent;
+	 GkrPkIndex *index;
+};
+
+struct _GkrPkSessionStorageClass {
+	GkrPkStorageClass parent_class;
+};
+
+GType                   gkr_pk_session_storage_get_type          (void) G_GNUC_CONST;
+
+GkrPkSessionStorage*    gkr_pk_session_storage_new               (void);
+
+G_END_DECLS
+
+#endif /* __GKR_PK_SESSION_STORAGE_H__ */

Added: trunk/pk/gkr-pk-storage.c
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-storage.c	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,840 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-storage.c - Base class for storage of PK objects
+
+   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 "gkr-pk-storage.h"
+#include "gkr-pk-util.h"
+
+#include "common/gkr-cleanup.h"
+#include "common/gkr-location.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyrings.h"
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+typedef struct _GkrPkStoragePrivate GkrPkStoragePrivate;
+
+struct _GkrPkStoragePrivate {
+	GHashTable *objects;
+	GHashTable *objects_by_location;
+	GkrPkIndex *index;
+};
+
+G_DEFINE_TYPE(GkrPkStorage, gkr_pk_storage, G_TYPE_OBJECT);
+
+#define GKR_PK_STORAGE_GET_PRIVATE(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GKR_TYPE_PK_STORAGE, GkrPkStoragePrivate))
+
+static GSList *registered_storages = NULL;
+static GkrPkStorage *default_storage = NULL;
+
+#define NO_VALUE GUINT_TO_POINTER (TRUE)
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+ 
+static void 
+cleanup_storages (void *unused)
+{
+	GSList *l;
+	for (l = registered_storages; l; l = g_slist_next (l))
+		g_object_unref (l->data);
+	g_slist_free (registered_storages);
+	registered_storages = NULL;
+	default_storage = NULL;
+}
+
+static void
+free_array (gpointer data)
+{
+	if (data)
+		g_array_free ((GArray*)data, TRUE);	
+}
+
+static void
+add_object_to_multihash (GHashTable *table, gpointer key, GkrPkObject *object)
+{
+	GArray *objs = (GArray*)g_hash_table_lookup (table, key);
+		
+	/* Add automatically if first at location */
+	if (!objs) {
+		objs = g_array_new (FALSE, TRUE, sizeof (GkrPkObject*));
+		g_hash_table_replace (table, key, objs);
+	}
+		
+	g_array_append_val (objs, object);
+}
+
+static gboolean
+remove_object_from_multihash (GHashTable *table, gconstpointer key, GkrPkObject *object)
+{
+	GArray *objs;
+	guint i; 
+	
+	objs = (GArray*)g_hash_table_lookup (table, key);
+	if (!objs)
+		return FALSE;
+		
+	for (i = 0; i < objs->len; ++i) {
+		if (g_array_index (objs, GkrPkObject*, i) == object)
+			break;
+	}
+
+	/* Not found */
+	if (i == objs->len)
+		return FALSE;	
+
+	g_array_remove_index_fast (objs, i);
+		
+	/* Remove automatically if last one */
+	if (objs->len == 0)
+		g_hash_table_remove (table, key);
+		
+	return TRUE;
+}
+
+static const gchar*
+prepare_ask_load_title (GQuark type)
+{
+	/*
+	 * Yes this is unmaintainable and stupid, but is required 
+	 * for translations to work properly.
+	 */
+	if (type == GKR_PKIX_PRIVATE_KEY)
+		return _("Unlock private key");
+	else if (type == GKR_PKIX_CERTIFICATE)
+		return _("Unlock certificate");
+	else if (type == GKR_PKIX_PUBLIC_KEY)
+		return _("Unlock public key");
+	else 
+		return _("Unlock");
+}
+
+static const gchar*
+prepare_ask_store_title (GQuark type)
+{
+	/*
+	 * Yes this is unmaintainable and stupid, but is required 
+	 * for translations to work properly.
+	 */
+	if (type == GKR_PKIX_PRIVATE_KEY)
+		return _("Lock private key");
+	else 
+		return _("Lock");
+}
+
+static const gchar*
+prepare_ask_load_primary (GQuark type)
+{
+	/*
+	 * Yes this is unmaintainable and dumb, but is required 
+	 * for translations to work properly.
+	 */
+	if (type == GKR_PKIX_PRIVATE_KEY)
+		return _("Enter password to unlock the private key");
+	else if (type == GKR_PKIX_CERTIFICATE)
+		return _("Enter password to unlock the certificate");
+	else if (type == GKR_PKIX_PUBLIC_KEY)
+		return _("Enter password to unlock the public key");
+	else 
+		return _("Enter password to unlock");
+}
+
+static const gchar*
+prepare_ask_store_primary (GQuark type)
+{
+	/*
+	 * Yes this is unmaintainable and dumb, but is required 
+	 * for translations to work properly.
+	 */
+	if (type == GKR_PKIX_PRIVATE_KEY)
+		return _("Enter password to protect the private key");
+	else 
+		return _("Enter password to protect storage");
+}
+
+static const gchar*
+prepare_ask_check (GQuark type)
+{
+	/*
+	 * Yes this is unmaintainable and stupid, but is required 
+	 * for translations to work properly.
+	 */
+	if (type == GKR_PKIX_PRIVATE_KEY)
+		return _("Automatically unlock this private key when I log in.");
+	else if (type == GKR_PKIX_CERTIFICATE)
+		return _("Automatically unlock this certificate when I log in.");
+	else if (type == GKR_PKIX_PUBLIC_KEY)
+		return _("Automatically unlock this public key when I log in.");
+	else 
+		return _("Automatically unlock this when I log in");
+}
+
+static gchar*
+prepare_ask_load_secondary (GQuark type, gboolean indexed, const gchar *label)
+{
+	/*
+	 * Yes this is unmaintainable and stupid, but is required 
+	 * for translations to work properly.
+	 */
+
+	/* When we've already indexed this data */
+	if (indexed) {
+
+		if (type == GKR_PKIX_PRIVATE_KEY)
+			return g_strdup_printf (_("An application wants access to the private key '%s', but it is locked"), label);
+		else if (type == GKR_PKIX_CERTIFICATE)
+			return g_strdup_printf (_("An application wants access to the certificate '%s', but it is locked"), label);
+		else if (type == GKR_PKIX_PUBLIC_KEY)
+			return g_strdup_printf (_("An application wants access to the public key '%s', but it is locked"), label);
+		else 
+			return g_strdup_printf (_("An application wants access to '%s', but it is locked"), label);
+	
+	/* Never before seen this data */ 
+	} else {
+
+		if (type == GKR_PKIX_PRIVATE_KEY)
+			return g_strdup_printf (_("The system wants to import the private key '%s', but it is locked"), label);
+		else if (type == GKR_PKIX_CERTIFICATE)
+			return g_strdup_printf (_("The system wants to import the certificate '%s', but it is locked"), label);
+		else if (type == GKR_PKIX_PUBLIC_KEY)
+			return g_strdup_printf (_("The system wants to import the public key '%s', but it is locked"), label);
+		else 
+			return g_strdup_printf (_("The system wants to import '%s', but it is locked"), label);
+	}
+}
+
+static gchar*
+prepare_ask_store_secondary (GQuark type, const gchar *label)
+{
+	/*
+	 * Yes this is unmaintainable and stupid, but is required 
+	 * for translations to work properly.
+	 */
+
+	if (type == GKR_PKIX_PRIVATE_KEY)
+		return g_strdup_printf (_("The system wants to store to the private key '%s' on your disk. Please enter a password to lock it with."), label);
+	else 
+		return g_strdup_printf (_("The system wants to store to '%s' on your disk. Please enter a password to lock it with."), label);
+}
+
+static void
+remove_each_object (GkrPkObject *object, gpointer unused, GkrPkStorage *storage)
+{
+	gkr_pk_storage_del_object (storage, object);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkr_pk_storage_init (GkrPkStorage *storage)
+{
+ 	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+ 	
+ 	pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
+ 	pv->objects_by_location = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, free_array);
+ 	pv->index = NULL;
+}
+
+static void 
+gkr_pk_storage_internal_refresh (GkrPkStorage *storage)
+{
+	/* By default we do nothing */
+}
+
+static gboolean 
+gkr_pk_storage_internal_load (GkrPkStorage *storage, GkrPkObject *object, GError **err)
+{
+	/* By default we do nothing */
+	return TRUE;
+}
+
+static gboolean 
+gkr_pk_storage_internal_store (GkrPkStorage *storage, GkrPkObject *object, GError **err)
+{
+	g_return_val_if_fail (object->storage == NULL, FALSE);
+	
+	/* By default just add the object */
+	gkr_pk_storage_add_object (storage, object);
+	return TRUE;
+}
+
+static gboolean 
+gkr_pk_storage_internal_remove (GkrPkStorage *storage, GkrPkObject *object, GError **err)
+{
+	g_return_val_if_fail (object->storage == storage, FALSE);
+
+	/* By default we just remove the object */
+	gkr_pk_storage_del_object (storage, object);
+	return TRUE;
+}
+
+static GkrPkIndex* 
+gkr_pk_storage_internal_index (GkrPkStorage *storage, GQuark unused)
+{
+ 	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+	GQuark kloc;
+	
+	if (!pv->index) {
+		/* We default to a keyring stored on the computer */
+		kloc = gkr_location_from_child (GKR_LOCATION_VOLUME_LOCAL, 
+		                                "pk-storage.keyring");
+	
+		pv->index = gkr_pk_index_open (kloc, "pk-storage", NULL);
+		g_return_val_if_fail (pv->index, NULL);
+	}
+	
+	return pv->index;
+}
+
+static void
+gkr_pk_storage_dispose (GObject *obj)
+{
+ 	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (obj);
+ 	
+ 	g_hash_table_remove_all (pv->objects_by_location);
+ 	g_hash_table_remove_all (pv->objects);
+ 	
+ 	if (pv->index)
+ 		g_object_unref (pv->index);
+ 	pv->index = NULL;
+ 	
+	G_OBJECT_CLASS (gkr_pk_storage_parent_class)->dispose (obj);
+}
+
+static void
+gkr_pk_storage_finalize (GObject *obj)
+{
+ 	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (obj);
+ 	
+ 	g_hash_table_destroy (pv->objects);
+	g_hash_table_destroy (pv->objects_by_location);
+	g_assert (pv->index == NULL);
+	
+	G_OBJECT_CLASS (gkr_pk_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_pk_storage_class_init (GkrPkStorageClass *klass)
+{
+	GObjectClass *gobject_class;
+
+	gkr_pk_storage_parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class = (GObjectClass*)klass;
+	gobject_class->dispose = gkr_pk_storage_dispose;
+	gobject_class->finalize = gkr_pk_storage_finalize;
+	
+	klass->refresh = gkr_pk_storage_internal_refresh;
+	klass->load = gkr_pk_storage_internal_load;
+	klass->store = gkr_pk_storage_internal_store;
+	klass->remove = gkr_pk_storage_internal_remove;
+	klass->index = gkr_pk_storage_internal_index;
+
+	gkr_cleanup_register (cleanup_storages, NULL);
+
+	g_type_class_add_private (gobject_class, sizeof (GkrPkStoragePrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+void
+gkr_pk_storage_register (GkrPkStorage *storage, gboolean is_default)
+{
+	g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+	g_object_ref (storage);
+	registered_storages = g_slist_prepend (registered_storages, storage);
+	if (is_default)
+		default_storage = storage;
+}
+
+void
+gkr_pk_storage_refresh_all (void)
+{
+	GSList *l;
+	for (l = registered_storages; l; l = g_slist_next (l))
+		gkr_pk_storage_refresh (GKR_PK_STORAGE (l->data));
+}
+
+void
+gkr_pk_storage_refresh (GkrPkStorage *storage)
+{
+	GkrPkStorageClass *klass;
+	
+	if (!storage) {
+		g_return_if_fail (default_storage);
+		storage = default_storage;
+	}
+
+	g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+	klass = GKR_PK_STORAGE_GET_CLASS (storage);
+	g_return_if_fail (klass->refresh);
+	(klass->refresh) (storage);
+}
+
+gboolean
+gkr_pk_storage_load (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+	GkrPkStorageClass *klass;
+
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+
+	if (!storage) {
+		g_return_val_if_fail (obj->storage, FALSE);
+		storage = obj->storage;
+	}
+
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+	klass = GKR_PK_STORAGE_GET_CLASS (storage);
+	g_return_val_if_fail (klass->load, FALSE);
+	return (klass->load) (storage, obj, err);	
+}
+
+gboolean
+gkr_pk_storage_store (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+	GkrPkStorageClass *klass;
+	gboolean ret;
+	
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
+	if (!storage) {
+		g_return_val_if_fail (default_storage, FALSE);
+		storage = default_storage;
+	}
+
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+	klass = GKR_PK_STORAGE_GET_CLASS (storage);
+	g_return_val_if_fail (klass->store, FALSE);
+	ret = (klass->store) (storage, obj, err);
+	
+	
+	if (!ret)
+		return FALSE;
+	
+	/* Check to make sure the storage is working properly */
+	if (!obj->digest)
+		g_warning ("no digest setup on object after storing");
+	if (obj->storage != storage)
+		g_warning ("wrong storage setup on object after storing");
+	
+	return TRUE;
+}
+
+gboolean 
+gkr_pk_storage_remove (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+	GkrPkStorageClass *klass;
+	
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
+	if (!storage) {
+		g_return_val_if_fail (obj->storage, FALSE);
+		storage = obj->storage;
+	}
+
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+	klass = GKR_PK_STORAGE_GET_CLASS (storage);
+	g_return_val_if_fail (klass->remove, FALSE);
+	return (klass->remove) (storage, obj, err);	
+}
+
+GkrPkIndex*
+gkr_pk_storage_index (GkrPkStorage *storage, GQuark location)
+{
+	GkrPkStorageClass *klass;
+
+	if (!storage)
+		storage = default_storage;
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), NULL);
+
+	klass = GKR_PK_STORAGE_GET_CLASS (storage);
+	g_return_val_if_fail (klass->index, NULL);
+	return (klass->index) (storage, location);
+}
+
+void
+gkr_pk_storage_set_object (GkrPkStorage *storage, GkrPkObject *object)
+{
+	g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (object->location);
+
+	g_object_ref (object);
+	
+	gkr_pk_storage_clr_objects (storage, object->location);
+	gkr_pk_storage_add_object (storage, object);
+	
+	g_object_unref (object);
+}
+
+void
+gkr_pk_storage_add_object (GkrPkStorage *storage, GkrPkObject *object)
+{
+	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+	gpointer k;
+		
+	g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (object->location);
+	
+	if (g_hash_table_lookup (pv->objects, object))
+		return;
+			
+	/* Mapping of location to the index key */
+	k = GUINT_TO_POINTER (object->location);
+	add_object_to_multihash (pv->objects_by_location, k, object); 
+
+	/* The storage of this object is ours from now on */
+	g_object_set (object, "storage", storage, NULL);
+		
+	/* Take ownership of the object */
+	g_object_ref (object);
+	g_hash_table_insert (pv->objects, object, NO_VALUE);
+}
+
+void
+gkr_pk_storage_del_object (GkrPkStorage *storage, GkrPkObject *object)
+{
+ 	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+	gpointer k;
+
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+	g_return_if_fail (object->location);
+	
+	if (!g_hash_table_lookup (pv->objects, object))
+		return;
+		
+	/* Mapping of location to the object */
+	k = GUINT_TO_POINTER (object->location);
+	if (!remove_object_from_multihash (pv->objects_by_location, k, object))
+		g_assert (FALSE);
+
+	/* Relinquish ownership of this object */
+	if (object->storage == storage)
+		g_object_set (object, "storage", storage, NULL);
+
+	/* Release ownership */
+	if (!g_hash_table_remove (pv->objects, object))
+		g_assert (FALSE);
+}
+
+void
+gkr_pk_storage_clr_objects (GkrPkStorage *storage, GQuark loc)
+{
+	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+	GArray *objs, *copy;
+	gpointer k;
+	guint i;
+		
+	/* Remove everything that is at that location */
+	k = GUINT_TO_POINTER (loc);
+	objs = (GArray*)g_hash_table_lookup (pv->objects_by_location, k);
+	if (!objs)
+		return;
+			
+	/* When removing we cleanup empty arrays */
+	g_assert (objs->len);
+
+	/* We copy because otherwise the array will change from underneath us */
+	copy = g_array_sized_new (FALSE, FALSE, sizeof (GkrPkObject*), objs->len);
+	g_array_append_vals (copy, objs->data, objs->len);
+	for (i = 0; i < copy->len; ++i)
+		gkr_pk_storage_del_object (storage, g_array_index (copy, GkrPkObject*, i));
+		 
+	g_array_free (copy, TRUE);
+}
+
+GkrPkChecks*
+gkr_pk_storage_checks_prepare (GkrPkStorage *storage, GQuark location)
+{
+ 	GkrPkStoragePrivate *pv = GKR_PK_STORAGE_GET_PRIVATE (storage);
+	GHashTable *checks;
+	GkrPkObject *object;
+	GArray *objs;
+	gpointer k;
+	guint i;
+	
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), NULL);
+	g_return_val_if_fail (location != 0, NULL);
+
+	checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, 
+	                                g_object_unref, NULL);
+
+	/* Create a table of what is at the location */
+	k = GUINT_TO_POINTER (location);
+	objs = (GArray*)g_hash_table_lookup (pv->objects_by_location, k);
+	for (i = 0; objs && i < objs->len; ++i) {
+		object = g_array_index (objs, GkrPkObject*, i);
+		g_object_ref (object);
+		g_hash_table_replace (checks, object, NO_VALUE);
+	} 
+	
+	return checks;
+}
+
+void
+gkr_pk_storage_checks_mark (GkrPkChecks *checks, GkrPkObject *object)
+{
+	g_return_if_fail (GKR_IS_PK_OBJECT (object));
+	g_return_if_fail (checks);
+
+	g_hash_table_remove (checks, object);
+}
+
+void
+gkr_pk_storage_checks_purge (GkrPkStorage *storage, GkrPkChecks *checks)
+{
+	g_return_if_fail (GKR_IS_PK_STORAGE (storage));
+	g_return_if_fail (checks);
+	
+	g_hash_table_foreach (checks, (GHFunc)remove_each_object, storage);
+	g_hash_table_destroy (checks);
+}
+
+gboolean
+gkr_pk_storage_get_store_password (GkrPkStorage *storage, GQuark location,
+                                   GQuark type, const gchar *label, gboolean *save,
+                                   gchar **result)
+{
+	GkrAskRequest *ask;
+	gchar *custom_label = NULL;
+	gchar *secondary;
+	gchar *display = NULL;
+	gboolean ret;
+	guint flags;
+	GkrKeyring *login;
+	
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (save != NULL, FALSE);
+	
+	*save = FALSE;
+
+	/* See if we can just use the login keyring password for this */
+	if (gkr_keyring_login_is_usable ()) {
+		login = gkr_keyrings_get_login ();
+		g_return_val_if_fail (login, FALSE);
+		g_return_val_if_fail (login->password, FALSE);
+		
+		*result = gkr_secure_strdup (login->password);
+		
+		/* 
+		 * Always same a 'login' password used as a secret. So that 
+		 * the user can later change the login password, and this'll 
+		 * still work. 
+		 */ 
+		*save = TRUE;
+		return TRUE;
+	}
+
+	if (!label) 
+		label = display = gkr_location_to_display (location);
+		
+	/* Build up the prompt */
+	flags = GKR_ASK_REQUEST_NEW_PASSWORD;
+	ask = gkr_ask_request_new (prepare_ask_store_title (type), 
+	                           prepare_ask_store_primary (type), flags);
+
+	secondary = prepare_ask_store_secondary (type, label); 
+	gkr_ask_request_set_secondary (ask, secondary);
+	g_free (secondary);
+
+	gkr_ask_request_set_location (ask, location);
+			
+	if (gkr_keyring_login_is_usable ())
+		gkr_ask_request_set_check_option (ask, prepare_ask_check (type));
+		
+	/* Prompt the user */
+	gkr_ask_daemon_process (ask);
+
+	/* If the user denied ... */
+	if (ask->response == GKR_ASK_RESPONSE_DENY) {
+		ret = FALSE;
+		
+	/* User cancelled or failure */
+	} else if (ask->response < GKR_ASK_RESPONSE_ALLOW) {
+		ret = FALSE;
+			
+	/* Successful response */
+	} else {
+		*result = gkr_secure_strdup (ask->typed_password);
+		*save = ask->checked;
+	}
+	
+	g_free (display);
+	g_free (custom_label);
+	g_object_unref (ask);
+	return ret;	
+}
+
+gboolean
+gkr_pk_storage_get_load_password (GkrPkStorage *storage, GQuark location, gkrconstid digest, 
+                                  GQuark type, const gchar *label, gint *state, 
+                                  gchar **result)
+{
+	GkrAskRequest *ask;
+	gchar *custom_label = NULL;
+	gchar *stype, *secondary;
+	gchar *display = NULL;
+	gboolean ret;
+	GkrPkIndex *index;
+	gboolean importing = FALSE;
+	gint st;
+	guint flags;
+	
+	g_return_val_if_fail (GKR_IS_PK_STORAGE (storage), FALSE);
+	g_return_val_if_fail (digest != NULL, FALSE);
+	g_return_val_if_fail (state != NULL, FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	
+	st = *state;
+	(*state)++;
+
+	/* 
+	 * On the first pass always try a NULL and then an empty password. 
+	 * This helps with two things.
+	 *  
+	 * 1. Often code will call this function, without actually parsing
+	 *    any data yet. So this prevents us prompting the user without
+	 *    knowing it will parse. 
+	 *  
+	 * 2. In case it is actually an empty password, we don't want to 
+	 *    prompt the user, just 'decrypt' it. Note that some systems
+	 *    use the null password instead of empty, so we try both.
+	 */
+
+	if (st == 0) {
+		*result = gkr_secure_strdup ("");
+		return TRUE;
+		
+	} else if (st == 1) {
+		*result = NULL;
+		return TRUE;	
+	}
+	
+	index = gkr_pk_storage_index (storage, location);
+	g_return_val_if_fail (index, FALSE);
+	
+	/*
+	 * The password prompting is somewhat convoluted with the end goal of 
+	 * not prompting the user more than necessary. 
+	 * 
+	 *  - Check and see if we have a password on record for this.
+	 *  - Don't prompt unless the user is specifically requesting 
+	 *    this object *or* we've never seen it before. 
+	 *  - Make note of everything we've prompted for so that later 
+	 *    we can note having seen it.
+	 */ 
+		
+	/* See if we can find a valid password for this location */
+	if (st == 2) {
+		*result = gkr_pk_index_get_secret (index, digest);
+		if (*result != NULL)
+			 return TRUE;
+		
+	/* If we've already tried this password unsuccesfully, then clear */
+	} else {
+		gkr_pk_index_set_secret (index, digest, NULL);
+	}
+
+	/*
+	 * If we've parsed this before, then we can lookup in our index as to what 
+	 * exactly this is we're talking about here.  
+	 */
+	stype = gkr_pk_index_get_string (index, digest, "parsed-type");
+	if (stype) {
+		if (!type && stype[0])
+			type = g_quark_from_string (stype);
+		g_free (stype);
+	}
+		
+	/* TODO: Load a better label if we have one */
+	custom_label = NULL;
+		
+	if (custom_label != NULL)
+		label = custom_label;
+	
+	if (!label) 
+		label = display = gkr_location_to_display (location);
+		
+	/* Build up the prompt */
+	if (importing)
+		flags = GKR_ASK_REQUEST_PASSWORD | GKR_ASK_REQUEST_OK_CANCEL_BUTTONS;
+	else
+		flags = GKR_ASK_REQUEST_PASSWORD | GKR_ASK_REQUEST_OK_DENY_BUTTONS;
+	ask = gkr_ask_request_new (prepare_ask_load_title (type), 
+	                           prepare_ask_load_primary (type), flags);
+
+	secondary = prepare_ask_load_secondary (type, !importing, label); 
+	gkr_ask_request_set_secondary (ask, secondary);
+	g_free (secondary);
+
+	gkr_ask_request_set_location (ask, location);
+			
+	if (gkr_keyring_login_is_usable ())
+		gkr_ask_request_set_check_option (ask, prepare_ask_check (type));
+		
+	/* Prompt the user */
+	gkr_ask_daemon_process (ask);
+
+	/* If the user denied ... */
+	if (ask->response == GKR_ASK_RESPONSE_DENY) {
+		ret = FALSE;
+		
+	/* User cancelled or failure */
+	} else if (ask->response < GKR_ASK_RESPONSE_ALLOW) {
+		ret = FALSE;
+			
+	/* Successful response */
+	} else {
+		*result = gkr_secure_strdup (ask->typed_password);
+		if (ask->checked) 
+			gkr_pk_index_set_secret (index, digest, ask->typed_password);
+	}
+	
+	g_free (display);
+	g_free (custom_label);
+	g_object_unref (ask);
+	return ret;
+}

Added: trunk/pk/gkr-pk-storage.h
==============================================================================
--- (empty file)
+++ trunk/pk/gkr-pk-storage.h	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,123 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pk-storage.h - Base class for storage of PK objects
+
+   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>
+*/
+
+#ifndef __GKR_PK_STORAGE_H__
+#define __GKR_PK_STORAGE_H__
+
+#include <gcrypt.h>
+#include <glib-object.h>
+
+#include "gkr-pk-index.h"
+#include "gkr-pk-object.h"
+
+G_BEGIN_DECLS
+
+#define GKR_TYPE_PK_STORAGE             (gkr_pk_storage_get_type ())
+#define GKR_PK_STORAGE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_PK_STORAGE, GkrPkStorage))
+#define GKR_PK_STORAGE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_PK_STORAGE, GkrPkStorageClass))
+#define GKR_IS_PK_STORAGE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_PK_STORAGE))
+#define GKR_IS_PK_STORAGE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_PK_STORAGE))
+#define GKR_PK_STORAGE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_PK_STORAGE, GkrPkStorageClass))
+
+typedef struct _GkrPkStorageClass GkrPkStorageClass;
+
+struct _GkrPkStorage {
+	 GObject parent;
+};
+
+struct _GkrPkStorageClass {
+	GObjectClass parent_class;
+
+	/* virtual methods */
+	void (*refresh) (GkrPkStorage *storage);
+	gboolean (*load) (GkrPkStorage *storage, GkrPkObject *object, GError **err);
+	gboolean (*store) (GkrPkStorage *storage, GkrPkObject *object, GError **err);
+	gboolean (*remove) (GkrPkStorage *storage, GkrPkObject *object, GError **err);
+	GkrPkIndex* (*index) (GkrPkStorage *storage, GQuark location);
+};
+
+GType                   gkr_pk_storage_get_type           (void) G_GNUC_CONST;
+
+void                    gkr_pk_storage_register           (GkrPkStorage *storage, 
+                                                           gboolean default_storage);
+
+void                    gkr_pk_storage_refresh_all        (void);
+
+void                    gkr_pk_storage_refresh            (GkrPkStorage *storage);
+
+gboolean                gkr_pk_storage_load               (GkrPkStorage *storage, 
+                                                           GkrPkObject *obj, GError **err);
+
+gboolean                gkr_pk_storage_store              (GkrPkStorage *storage,
+                                                           GkrPkObject *obj, GError **err);
+
+gboolean                gkr_pk_storage_remove             (GkrPkStorage *storage,
+                                                           GkrPkObject *obj, GError **err);
+
+GkrPkIndex*             gkr_pk_storage_index              (GkrPkStorage *storage, 
+                                                           GQuark location);
+
+/* For use by derived classes */
+
+GkrPkIndex*             gkr_pk_storage_create_index       (GkrPkStorage *storage,
+                                                           GQuark index_location);
+
+void                    gkr_pk_storage_set_object         (GkrPkStorage *storage, 
+                                                           GkrPkObject *obj);
+
+void                    gkr_pk_storage_add_object         (GkrPkStorage *storage, 
+                                                           GkrPkObject *obj);
+
+void                    gkr_pk_storage_del_object         (GkrPkStorage *storage, 
+                                                           GkrPkObject *obj);
+
+void                    gkr_pk_storage_clr_objects        (GkrPkStorage *storage, 
+                                                           GQuark location);
+
+typedef GHashTable GkrPkChecks;
+
+GkrPkChecks*            gkr_pk_storage_checks_prepare     (GkrPkStorage *storage, 
+                                                           GQuark location);
+
+void                    gkr_pk_storage_checks_mark        (GkrPkChecks *checks,
+                                                           GkrPkObject *object);
+
+void                    gkr_pk_storage_checks_purge       (GkrPkStorage *storage, 
+                                                           GkrPkChecks *checks);
+
+#define GKR_PK_STORAGE_PASSWD_STATE  	 0
+#define GKR_PK_STORAGE_PASSWD_PROMPT	 2
+
+gboolean                gkr_pk_storage_get_store_password (GkrPkStorage *storage, 
+                                                           GQuark location, GQuark type, 
+                                                           const gchar *label, gboolean *save, 
+                                                           gchar **passowrd);
+	
+gboolean                gkr_pk_storage_get_load_password  (GkrPkStorage *storage, 
+                                                           GQuark location, gkrconstid digest, 
+                                                           GQuark type, const gchar *label, 
+                                                           gint *state, gchar **password);
+
+G_END_DECLS
+
+#endif /* __GKR_PK_STORAGE_H__ */

Modified: trunk/pk/tests/unit-test-pk-cert.c
==============================================================================
--- trunk/pk/tests/unit-test-pk-cert.c	(original)
+++ trunk/pk/tests/unit-test-pk-cert.c	Mon Jul  7 21:17:26 2008
@@ -58,11 +58,15 @@
 static GkrPkCert *certificate_1 = NULL;
 static GkrPkCert *certificate_2 = NULL;
 static GkrPkObject *privkey_1 = NULL;
+static GkrPkIndex *pk_index = NULL;
 
 void unit_setup_certificate (void)
 {
 	/* Our own object manager */
-	manager = gkr_pk_object_manager_instance_for_client (1231); 
+	manager = gkr_pk_object_manager_instance_for_client (1231);
+	
+	/* Our own pk_index */
+	pk_index = gkr_pk_index_default ();
 }
 
 void unit_test_create_certificate (CuTest* cu)
@@ -172,17 +176,17 @@
 	
 	/* Mark as trusted */
 	/* TODO: Should do this via attribute once writable */
-	gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_2), "user-trust", "trusted");
+	gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_2), "user-trust", "trusted");
 	CHECK_ULONG_ATTRIBUTE (cu, certificate_2, CKA_GNOME_USER_TRUST, CKT_GNOME_TRUSTED);
 	
 	/* Should return to previous state */	
 	/* TODO: Should do this via attribute once writable */
-	gkr_pk_index_delete (GKR_PK_OBJECT (certificate_2), "user-trust");
+	gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_2), "user-trust");
 	CHECK_ULONG_ATTRIBUTE (cu, certificate_2, CKA_GNOME_USER_TRUST, CKT_GNOME_UNKNOWN);
 
 	/* Mark as untrusted */
 	/* TODO: Should do this via attribute once writable */
-	gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "untrusted");
+	gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "untrusted");
 	CHECK_ULONG_ATTRIBUTE (cu, certificate_1, CKA_GNOME_USER_TRUST, CKT_GNOME_UNTRUSTED);	
 }
 
@@ -226,10 +230,9 @@
 	CHECK_BOOL_ATTRIBUTE (cu, certificate_2, CKA_GNOME_PURPOSE_IPSEC_USER, CK_TRUE);
 	CHECK_BOOL_ATTRIBUTE (cu, certificate_2, CKA_GNOME_PURPOSE_TIME_STAMPING, CK_TRUE);
 
-	
 	/* Add a purpose */
 	/* TODO: Should do this via attribute once writable */
-	gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_2), "purposes", "some-purpose");
+	gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_2), "purposes", "some-purpose");
 	CHECK_BOOL_ATTRIBUTE (cu, certificate_2, CKA_GNOME_PURPOSE_RESTRICTED, CK_TRUE);
 	
 	memset (&attr, 0, sizeof (attr));

Modified: trunk/pk/tests/unit-test-pk-index.c
==============================================================================
--- trunk/pk/tests/unit-test-pk-index.c	(original)
+++ trunk/pk/tests/unit-test-pk-index.c	Mon Jul  7 21:17:26 2008
@@ -1,5 +1,5 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* unit-test-pk-index.c: Test PK Indexes
+/* unit-test-pk-pk_index.c: Test PK Indexes
 
    Copyright (C) 2007 Stefan Walter
 
@@ -51,17 +51,26 @@
 #define DATA_L (strlen ((gchar*)DATA))
 
 #define STR "a test string"
+#define DEFAULT "default-value"
 
 static GkrPkObject *object = NULL;
+static GkrPkIndex *pk_index = NULL;
 
 void unit_setup_index (void)
 {
+	GnomeKeyringAttributeList *defaults;
+	
 	/* This is just any arbitrary data */
 	gkrid id = gkr_id_new (DATA, DATA_L);
 	GQuark location = gkr_location_from_child (GKR_LOCATION_VOLUME_LOCAL, "woof");
 	
+	defaults = gnome_keyring_attribute_list_new ();
+	gnome_keyring_attribute_list_append_string (defaults, "test-default", DEFAULT);
+	
+	pk_index = gkr_pk_index_new (NULL, defaults);
+	
 	object = g_object_new (GKR_TYPE_PK_OBJECT, "location", location, "digest", id, NULL);
-	gkr_pk_index_clear (object);
+	gkr_pk_index_delete (pk_index, object->digest);
 }
 
 void unit_test_index_binary (CuTest* cu)
@@ -71,10 +80,10 @@
 	gsize n_data;
 	
 	/* Test binary */
-	ret = gkr_pk_index_set_binary (object, "field", DATA, DATA_L);
+	ret = gkr_pk_index_set_binary (pk_index, object->digest, "field", DATA, DATA_L);
 	CuAssert (cu, "set_binary returned false", ret);
 
-	data = gkr_pk_index_get_binary (object, "field", &n_data);
+	data = gkr_pk_index_get_binary (pk_index, object->digest, "field", &n_data);
 	CuAssert (cu, "get_binary returned no data", data != NULL);
 	CuAssert (cu, "get_binary returned bad length data", n_data == DATA_L);
 	CuAssert (cu, "get_binary returned wrong data", memcmp (data, DATA, DATA_L) == 0);
@@ -86,26 +95,26 @@
 	gboolean ret;
 	
 	/* Test strings */
-	ret = gkr_pk_index_set_string (object, "string", STR);
+	ret = gkr_pk_index_set_string (pk_index, object->digest, "string", STR);
 	CuAssert (cu, "set_string returned false", ret);
 
-	str = gkr_pk_index_get_string (object, "string");
+	str = gkr_pk_index_get_string (pk_index, object->digest, "string");
 	CuAssert (cu, "get_string returned no string", str != NULL);
 	CuAssert (cu, "get_string returned wrong string", strcmp (str, STR) == 0);
 }
 
 void unit_test_index_int (CuTest *cu)
 {
-	gint val;
+	guint val;
 	gboolean ret;
 	
-	ret = gkr_pk_index_set_int (object, "intval", 23423523);
+	ret = gkr_pk_index_set_uint (pk_index, object->digest, "intval", 23423523);
 	CuAssert (cu, "set_int returned false", ret);
 
-	val = gkr_pk_index_get_int (object, "intval", 0);
+	val = gkr_pk_index_get_uint (pk_index, object->digest, "intval", 0);
 	CuAssert (cu, "get_int returned wrong value", val == 23423523);
 
-	val = gkr_pk_index_get_int (object, "nonexistant", 35);
+	val = gkr_pk_index_get_uint (pk_index, object->digest, "nonexistant", 35);
 	CuAssert (cu, "get_int didn't return default", val == 35);
 }
 
@@ -114,13 +123,13 @@
 	gboolean val;
 	gboolean ret;
 	
-	ret = gkr_pk_index_set_boolean (object, "boolval", TRUE);
+	ret = gkr_pk_index_set_boolean (pk_index, object->digest, "boolval", TRUE);
 	CuAssert (cu, "set_boolean returned false", ret);
 
-	val = gkr_pk_index_get_boolean (object, "boolval", 0);
+	val = gkr_pk_index_get_boolean (pk_index, object->digest, "boolval", 0);
 	CuAssert (cu, "get_boolean returned wrong value", val == TRUE);
 
-	val = gkr_pk_index_get_boolean (object, "nonexistant", TRUE);
+	val = gkr_pk_index_get_boolean (pk_index, object->digest, "nonexistant", TRUE);
 	CuAssert (cu, "get_boolean didn't return default", val == TRUE);
 }
 
@@ -135,20 +144,20 @@
 	for (i = 0; i < 4; ++i)
 		quarks[i] = g_quark_from_static_string ("blah");
 	
-	ret = gkr_pk_index_set_quarks (object, "quarks", quarks);
+	ret = gkr_pk_index_set_quarks (pk_index, object->digest, "quarks", quarks);
 	CuAssert (cu, "set_quarks returned false", ret);
 	
 	/* A second time which exercises internals to not write same value twice */
-	ret = gkr_pk_index_set_quarks (object, "quarks", quarks);
-	CuAssert (cu, "set_quarks returned false", ret);
+	ret = gkr_pk_index_set_quarks (pk_index, object->digest, "quarks", quarks);
+	CuAssert (cu, "set_quarks returned true, but shouldn't have written", !ret);
 	
-	output = gkr_pk_index_get_quarks (object, "quarks"); 
+	output = gkr_pk_index_get_quarks (pk_index, object->digest, "quarks"); 
 	CuAssert (cu, "get_quarks returned null", output != NULL);
 	
 	for (i = 0; i < 4; ++i)
 		CuAssert (cu, "returned quark is different", quarks[i] == output[i]);
 	
-	output = gkr_pk_index_get_quarks (object, "nonexistant");
+	output = gkr_pk_index_get_quarks (pk_index, object->digest, "nonexistant");
 	CuAssert (cu, "get_quarks didn't return null", output == NULL);
 }
 
@@ -157,25 +166,34 @@
 	gboolean ret;
 	gboolean val;
 	
-	ret = gkr_pk_index_delete (object, "boolval");
+	ret = gkr_pk_index_clear (pk_index, object->digest, "boolval");
 	CuAssert (cu, "delete returned false", ret);
 	
-	val = gkr_pk_index_get_boolean (object, "boolval", FALSE);
+	val = gkr_pk_index_get_boolean (pk_index, object->digest, "boolval", FALSE);
 	CuAssert (cu, "delete didn't work", val == FALSE);
 	
-	ret = gkr_pk_index_delete (object, "nonexistant");
-	CuAssert (cu, "delete returned false", ret);
+	ret = gkr_pk_index_clear (pk_index, object->digest, "nonexistant");
+	CuAssert (cu, "delete return true but should already be gone", !ret);
 }
 
 void unit_test_index_all (CuTest *cu)
 {
 	gboolean ret;
 	
-	ret = gkr_pk_index_have (object);
+	ret = gkr_pk_index_have (pk_index, object->digest);
 	CuAssert (cu, "didn't find anything for object", ret);
 	
-	gkr_pk_index_clear (object);
+	gkr_pk_index_delete (pk_index, object->digest);
 	
-	ret = gkr_pk_index_have (object);
+	ret = gkr_pk_index_have (pk_index, object->digest);
 	CuAssert (cu, "clear didn't work", !ret);
 }
+
+void unit_test_index_defaults (CuTest* cu)
+{
+	gchar *str;
+	
+	str = gkr_pk_index_get_string (pk_index, object->digest, "test-default");
+	CuAssert (cu, "couldn't find default value", str != NULL);
+	CuAssert (cu, "returned wrong default value", strcmp (DEFAULT, str) == 0);
+}

Modified: trunk/pk/tests/unit-test-pk-netscape-trust.c
==============================================================================
--- trunk/pk/tests/unit-test-pk-netscape-trust.c	(original)
+++ trunk/pk/tests/unit-test-pk-netscape-trust.c	Mon Jul  7 21:17:26 2008
@@ -57,11 +57,14 @@
 static GkrPkCert *certificate_2 = NULL;
 static GkrPkObject *trust_1 = NULL;
 static GkrPkObject *trust_2 = NULL;
+static GkrPkIndex *pk_index = NULL;
 
 void unit_setup_trust (void)
 {
 	/* Our own object manager */
-	manager = gkr_pk_object_manager_instance_for_client (12333); 
+	manager = gkr_pk_object_manager_instance_for_client (12333);
+	
+	pk_index = gkr_pk_index_default ();
 }
 
 void unit_test_create_trust (CuTest* cu)
@@ -80,8 +83,8 @@
 	CuAssert (cu, "gkr_pk_cert_new returned bad object", GKR_IS_PK_CERT (certificate_1));
 
 	/* Make sure this is trusted */
-	gkr_pk_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "trusted");
-	gkr_pk_index_delete (GKR_PK_OBJECT (certificate_1), "purposes");
+	gkr_pk_object_index_set_string (GKR_PK_OBJECT (certificate_1), "user-trust", "trusted");
+	gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_1), "purposes");
 	
 	/* Should have created netscape trust companion object */
 	keyid = gkr_pk_cert_get_keyid (certificate_1);
@@ -96,8 +99,8 @@
 	CuAssert (cu, "gkr_pk_cert_new returned bad object", GKR_IS_PK_CERT (certificate_2));
 
 	/* Make sure this is not trusted */
-	gkr_pk_index_delete (GKR_PK_OBJECT (certificate_2), "user-trust");
-	gkr_pk_index_delete (GKR_PK_OBJECT (certificate_2), "purposes");
+	gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_2), "user-trust");
+	gkr_pk_object_index_clear (GKR_PK_OBJECT (certificate_2), "purposes");
 	
 	/* Should have created netscape trust companion object */
 	keyid = gkr_pk_cert_get_keyid (certificate_2);

Modified: trunk/pkcs11/gkr-pkcs11-daemon-session.c
==============================================================================
--- trunk/pkcs11/gkr-pkcs11-daemon-session.c	(original)
+++ trunk/pkcs11/gkr-pkcs11-daemon-session.c	Mon Jul  7 21:17:26 2008
@@ -41,7 +41,8 @@
 
 #include "pk/gkr-pk-object.h"
 #include "pk/gkr-pk-object-manager.h"
-#include "pk/gkr-pk-object-storage.h"
+#include "pk/gkr-pk-session-storage.h"
+#include "pk/gkr-pk-storage.h"
 #include "pk/gkr-pk-util.h"
 
 #include <stdlib.h>
@@ -76,7 +77,7 @@
 	guint deverror;                 /* The 'device' error code */
 	
 	GkrPkObjectManager *manager;	/* The object manager for this session */
-	GHashTable *objects;		/* Objects owned by the session */
+	GkrPkStorage *storage;          /* Objects owned by the session */
 };
 
 /* 
@@ -86,24 +87,6 @@
 #define PROTOCOL_ERROR   CKR_DEVICE_ERROR
 
 /* -----------------------------------------------------------------------------
- * SESSION OBJECTS 
- */
-
-static void
-session_add_object (SessionInfo *sinfo, GkrPkObject *object)
-{
-	g_assert (sinfo);
-	
-	g_return_if_fail (object->handle != 0);
-	g_return_if_fail (object->location == 0);
-	g_return_if_fail (object->manager == sinfo->manager);
-
-	/* We assume the ownership */
-	g_object_ref (object);
-	g_hash_table_insert (sinfo->objects, GUINT_TO_POINTER (object->handle), object);
-}
-
-/* -----------------------------------------------------------------------------
  * HELPERS
  */
  
@@ -492,22 +475,22 @@
 		goto done;
 
 	g_return_val_if_fail (object, CKR_GENERAL_ERROR);
-		
+	g_return_val_if_fail (object->storage == NULL, CKR_GENERAL_ERROR);
+
 	/* Token objects get stored in the main object storage */
-	if (token) {
-		g_return_val_if_fail (object->storage != NULL, CKR_GENERAL_ERROR);
-		res = gkr_pk_object_storage_add (gkr_pk_object_storage_get (), object, &err);
-		if (!res) {
-			g_warning ("couldn't write created object to disk: %s", 
-			           err && err->message ? err->message : "");
-			g_clear_error (&err);
-			ret = CKR_GENERAL_ERROR;
-			goto done;
-		}
-			
+	if (token) 
+		res = gkr_pk_storage_store (NULL, object, &err);
+
 	/* Session objects are owned by the session */
-	} else {
-		session_add_object (sinfo, object);
+	else
+		res = gkr_pk_storage_store (sinfo->storage, object, &err);
+	
+	if (!res) {
+		g_warning ("couldn't write created object to disk: %s", 
+		           err && err->message ? err->message : "");
+		g_clear_error (&err);
+		ret = CKR_GENERAL_ERROR;
+		goto done;
 	}
 
 	gkr_pkcs11_message_write_uint32 (resp, object->handle);
@@ -572,7 +555,7 @@
 			return CKR_SESSION_READ_ONLY;
 			
 		g_return_val_if_fail (object->storage, CKR_GENERAL_ERROR);
-		res = gkr_pk_object_storage_remove (object->storage, object, &err);
+		res = gkr_pk_storage_remove (object->storage, object, &err);
 		if (!res) {
 			g_warning ("couldn't remove object from disk: %s", 
 			           err && err->message ? err->message : "");
@@ -1381,17 +1364,20 @@
 session_info_new ()
 {
 	SessionInfo *sinfo = g_new0 (SessionInfo, 1);
-	sinfo->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+	sinfo->storage = GKR_PK_STORAGE (gkr_pk_session_storage_new ());
 	return sinfo;
 }
 
 static void 
 session_info_free (SessionInfo *sinfo)
 {
-	if (sinfo->manager)
-		g_object_unref (sinfo->manager);
-	g_hash_table_destroy (sinfo->objects);
-	g_free (sinfo);
+	if (sinfo) {
+		if (sinfo->manager)
+			g_object_unref (sinfo->manager);
+		if (sinfo->storage)
+			g_object_unref (sinfo->storage);
+		g_free (sinfo);
+	}
 }
 
 static gboolean

Modified: trunk/pkix/gkr-pkix-marshal.list
==============================================================================
--- trunk/pkix/gkr-pkix-marshal.list	(original)
+++ trunk/pkix/gkr-pkix-marshal.list	Mon Jul  7 21:17:26 2008
@@ -1,3 +1,3 @@
 BOOLEAN:UINT,POINTER,UINT
 BOOLEAN:UINT,POINTER,UINT,POINTER
-POINTER:UINT,POINTER,UINT,STRING,UINT
+BOOLEAN:UINT,POINTER,UINT,STRING,POINTER,POINTER

Modified: trunk/pkix/gkr-pkix-openssl.c
==============================================================================
--- trunk/pkix/gkr-pkix-openssl.c	(original)
+++ trunk/pkix/gkr-pkix-openssl.c	Mon Jul  7 21:17:26 2008
@@ -257,3 +257,121 @@
 	
 	return GKR_PKIX_SUCCESS;
 }
+
+gboolean
+gkr_pkix_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, 
+                                const guchar *data, gsize n_data,
+                                guchar **encrypted, gsize *n_encrypted)
+{
+	gsize n_overflow, n_batch, n_padding;
+	gcry_cipher_hd_t ch;
+	guchar *key = NULL;
+	guchar *iv = NULL;
+	guchar *padded = NULL;
+	int gcry, ivlen;
+	int algo = 0;
+	int mode = 0;
+	
+	if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
+		g_return_val_if_reached (FALSE);
+		
+	ivlen = gcry_cipher_get_algo_blklen (algo);
+
+	/* We assume the iv is at least as long as at 8 byte salt */
+	g_return_val_if_fail (ivlen >= 8, FALSE);
+	
+	/* IV is already set from the DEK info */
+	if (!gkr_crypto_generate_symkey_simple (algo, GCRY_MD_MD5, password, 
+	                                        iv, 8, 1, &key, NULL))
+		g_return_val_if_reached (FALSE);
+	
+	gcry = gcry_cipher_open (&ch, algo, mode, 0);
+	g_return_val_if_fail (!gcry, FALSE);
+		
+	gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
+	g_return_val_if_fail (!gcry, FALSE);
+	gkr_secure_free (key);
+
+	/* 16 = 128 bits */
+	gcry = gcry_cipher_setiv (ch, iv, ivlen);
+	g_return_val_if_fail (!gcry, FALSE);
+	g_free (iv);
+	
+	/* Allocate output area */
+	n_overflow = (n_data % ivlen);
+	n_padding = n_overflow ? (ivlen - n_overflow) : 0;
+	n_batch = n_data - n_overflow;
+	*n_encrypted = n_data + n_padding;
+	*encrypted = g_malloc0 (*n_encrypted);
+	
+	g_assert (*n_encrypted % ivlen == 0);
+	g_assert (*n_encrypted >= n_data);
+	g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
+
+	/* Encrypt everything but the last bit */
+	gcry = gcry_cipher_encrypt (ch, *encrypted, n_batch, (void*)data, n_batch);
+	if (gcry) {
+		g_free (*encrypted);
+		g_return_val_if_reached (FALSE);
+	}
+	
+	/* Encrypt the padded block */
+	if (n_overflow) {
+		padded = gkr_secure_alloc (ivlen);
+		memset (padded, 0, ivlen);
+		memcpy (padded, data + n_batch, n_overflow);
+		gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen);
+		gkr_secure_free (padded);
+		if (gcry) {
+			g_free (*encrypted);
+			g_return_val_if_reached (FALSE);
+		}
+	}
+
+	gcry_cipher_close (ch);
+	return TRUE;
+}
+
+const gchar*
+gkr_pkix_openssl_get_dekinfo (GHashTable *headers)
+{
+	const gchar *val;
+	if (!headers)
+		return NULL;
+	val = g_hash_table_lookup (headers, "Proc-Type");
+	if (!val || strcmp (val, "4,ENCRYPTED") != 0)
+		return NULL;
+	val = g_hash_table_lookup (headers, "DEK-Info");
+	g_return_val_if_fail (val, NULL);
+	return val;
+}
+
+const gchar*
+gkr_pkix_openssl_prep_dekinfo (GHashTable *headers)
+{
+	gsize ivlen, len, n_encoded;
+	gchar buf[256];
+	guchar *iv;
+	const gchar *dekinfo;
+	
+	strcpy (buf, "DES-EDE3-CBC,");
+
+	/* Create the iv */
+	ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
+	g_return_val_if_fail (ivlen, NULL);
+	iv = g_malloc (ivlen);
+	gcry_create_nonce (iv, ivlen);
+	
+	/* And encode it into the string */
+	len = strlen (buf);
+	g_return_val_if_fail (sizeof (buf) - len > ivlen * 2, NULL);
+	n_encoded = (ivlen * 2) + 1;
+	if (!gkr_crypto_hex_encode (iv, ivlen, buf + len, &n_encoded))
+		g_return_val_if_reached (NULL);
+
+	dekinfo = g_strdup (buf);
+	g_hash_table_insert (headers, g_strdup ("DEK-Info"), (void*)dekinfo);
+	g_hash_table_insert (headers, g_strdup ("Proc-Type"), g_strdup ("4,ENCRYPTED"));
+	
+	return dekinfo;
+}

Modified: trunk/pkix/gkr-pkix-openssl.h
==============================================================================
--- trunk/pkix/gkr-pkix-openssl.h	(original)
+++ trunk/pkix/gkr-pkix-openssl.h	Mon Jul  7 21:17:26 2008
@@ -28,10 +28,18 @@
 
 #include "gkr-pkix-parser.h"
 
-int               gkr_pkix_openssl_parse_algo       (const gchar *name, int *mode);
+int              gkr_pkix_openssl_parse_algo        (const gchar *name, int *mode);
 
-GkrPkixResult    gkr_pkix_openssl_decrypt_block    (const gchar *dekinfo, const gchar *password, 
+gboolean         gkr_pkix_openssl_encrypt_block     (const gchar *dekinfo, const gchar *password, 
+                                                     const guchar *data, gsize n_data,
+                                                     guchar **encrypted, gsize *n_encrypted);
+
+GkrPkixResult    gkr_pkix_openssl_decrypt_block     (const gchar *dekinfo, const gchar *password, 
                                                      const guchar *data, gsize n_data, 
                                                      guchar **decrypted, gsize *n_decrypted);
 
+const gchar*     gkr_pkix_openssl_get_dekinfo       (GHashTable *headers);
+
+const gchar*     gkr_pkix_openssl_prep_dekinfo      (GHashTable *headers);
+
 #endif /*GKRPKIOPENSSL_H_*/

Modified: trunk/pkix/gkr-pkix-parser.c
==============================================================================
--- trunk/pkix/gkr-pkix-parser.c	(original)
+++ trunk/pkix/gkr-pkix-parser.c	Mon Jul  7 21:17:26 2008
@@ -111,12 +111,11 @@
 
 typedef struct {
 	GQuark location;
-	guint n_prompts;
-	guint n_passes;
+	gint ask_state;
 	GSList *seen;
 } PasswordState;
 
-#define PASSWORD_STATE_INIT { 0, 0, 0, NULL}
+#define PASSWORD_STATE_INIT { 0, 0, NULL}
 
 typedef struct {
 	GSList *seen_passwords;
@@ -149,8 +148,8 @@
 	GkrPkixParserPrivate *pv = GKR_PKIX_PARSER_GET_PRIVATE (parser);
 	gboolean first = FALSE;
 	gchar *display = NULL;
-	guint passes;
 	gchar *prompted;
+	gboolean result;
 	GSList *l;
 
 	if (gkr_async_is_stopping ())
@@ -159,36 +158,10 @@
 	/* Is it a new location, reset stuff */
 	if (loc != state->location) {
 		state->seen = NULL;
-		state->n_prompts = 0;
-		state->n_passes = 0;
+		state->ask_state = 0;
 		state->location = loc;
 	}
-	
-	passes = state->n_passes;
-	++state->n_passes;
-		
-	/* 
-	 * On the first pass always try a NULL and then an empty password. 
-	 * This helps with two things.
-	 *  
-	 * 1. Often code will call this function, without actually parsing
-	 *    any data yet. So this prevents us prompting the user without
-	 *    knowing it will parse. 
-	 *  
-	 * 2. In case it is actually an empty password, we don't want to 
-	 *    prompt the user, just 'decrypt' it. Note that some systems
-	 *    use the null password instead of empty, so we try both.
-	 */
-	if (passes == 0) {
-		*password = "";
-		return TRUE;
-	}
-	
-	if (passes == 1) {
-		*password = NULL;
-		return TRUE;
-	}
-	
+
 	/* 
 	 * Next passes we look through all the passwords that the parser 
 	 * has seen so far. This is because different parts of a encrypted
@@ -225,19 +198,19 @@
 	 * And lastly we actually prompt for a password. This prompt might
 	 * also lookup saved passwords for this location.
 	 */
-	 
 	if (!label) 
 		label = display = gkr_location_to_display (loc);
 	
 	g_signal_emit (parser, signals[ASK_PASSWORD], 0, 
-	               loc, digest, type, label, state->n_prompts, &prompted);
+	               loc, digest, type, label, &state->ask_state, 
+	               &prompted, &result);
 	               
-	++state->n_prompts;
 	g_free (display);
 	
 	/* Stash away any password */
-	if (prompted) {
-		pv->seen_passwords = g_slist_prepend (pv->seen_passwords, prompted);
+	if (result) {
+		if (prompted)
+			pv->seen_passwords = g_slist_prepend (pv->seen_passwords, prompted);
 		*password = prompted;
 		return TRUE;
 	}
@@ -287,21 +260,6 @@
 		asn1_delete_structure (&asn1);
 }
 
-static gboolean
-accumulate_password (GSignalInvocationHint *ihint, GValue *return_accu,
-                     const GValue *handler_return, gpointer data)
-{
-	gchar *password;
-	
-	password = g_value_get_pointer (handler_return);
-	if (!password)
-		return TRUE;
-		
-	/* Choose the first password returned by a handler */
-	g_value_set_pointer (return_accu, password);
-	return FALSE;
-}
-
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -337,11 +295,13 @@
 	return FALSE;
 }
 
-static gchar*
+static gboolean
 gkr_pkix_parser_ask_password (GkrPkixParser *parser, GQuark loc, gkrconstid digest,
-                              GQuark type, const gchar *details, guint n_prompts)
+                              GQuark type, const gchar *details, gint *state, 
+                              gchar **password)
 {
-	return NULL;
+	*password = NULL;
+	return FALSE;
 }
 	
 static void
@@ -392,8 +352,8 @@
 	/* Due to our use of secure memory, we use a pointer as the signal return type */
 	signals[ASK_PASSWORD] = g_signal_new ("ask-password", GKR_TYPE_PKIX_PARSER, 
 			G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GkrPkixParserClass, ask_password),
-			accumulate_password, NULL, gkr_pkix_marshal_POINTER__UINT_POINTER_UINT_STRING_UINT, 
-			G_TYPE_POINTER, 5, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT);
+			g_signal_accumulator_true_handled, NULL, gkr_pkix_marshal_BOOLEAN__UINT_POINTER_UINT_STRING_POINTER_POINTER, 
+			G_TYPE_BOOLEAN, 6, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
 			
 	g_type_class_add_private (klass, sizeof (GkrPkixParserPrivate));
 }

Modified: trunk/pkix/gkr-pkix-parser.h
==============================================================================
--- trunk/pkix/gkr-pkix-parser.h	(original)
+++ trunk/pkix/gkr-pkix-parser.h	Mon Jul  7 21:17:26 2008
@@ -70,9 +70,10 @@
 	                         gcry_sexp_t sexp);
 	
 	/* A callback for each password needed */
-	gchar* (*ask_password) (GkrPkixParser *parser, GQuark location, 
-	                        gkrconstid digest, GQuark type,
-	                        const gchar *orig_label, guint failed);
+	gboolean (*ask_password) (GkrPkixParser *parser, GQuark location, 
+	                          gkrconstid digest, GQuark type,
+	                          const gchar *orig_label, gint *state,
+	                          gchar **password);
 };
 
 GType               gkr_pkix_parser_get_type                (void) G_GNUC_CONST;

Modified: trunk/pkix/gkr-pkix-pem.c
==============================================================================
--- trunk/pkix/gkr-pkix-pem.c	(original)
+++ trunk/pkix/gkr-pkix-pem.c	Mon Jul  7 21:17:26 2008
@@ -82,7 +82,7 @@
         	g_strstrip (name);
         	
         	if (!*result)
-        		*result = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+        		*result = gkr_pkix_pem_headers_new ();
         	g_hash_table_replace (*result, name, value);
 	}
 
@@ -225,6 +225,12 @@
 	return TRUE;
 }
 
+GHashTable*
+gkr_pkix_pem_headers_new (void)
+{
+	return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
 guint
 gkr_pkix_pem_parse  (const guchar *data, gsize n_data, 
                      GkrPkixPemCallback callback, gpointer user_data)
@@ -279,3 +285,61 @@
 	return nfound;
 }
 
+static void 
+append_each_header (gpointer key, gpointer value, gpointer user_data)
+{
+	GString *string = (GString*)user_data;
+	
+	g_string_append (string, (gchar*)key);
+	g_string_append (string, ": ");
+	g_string_append (string, (gchar*)value);
+	g_string_append_c (string, '\n');
+}
+
+guchar*
+gkr_pkix_pem_write (const guchar *data, gsize n_data, GQuark type, 
+                    GHashTable *headers, gsize *n_result)
+{
+	GString *string;
+	gint state, save;
+	gsize length, n_prefix;
+	
+	g_return_val_if_fail (data || !n_data, NULL);
+	g_return_val_if_fail (type, NULL);
+	g_return_val_if_fail (n_result, NULL);
+
+	string = g_string_sized_new (4096);
+	
+	/* The prefix */
+	g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L);
+	g_string_append (string, g_quark_to_string (type));
+	g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
+	g_string_append_c (string, '\n');
+	
+	/* The headers */
+	if (headers && g_hash_table_size (headers) > 0) {
+		g_hash_table_foreach (headers, append_each_header, string);
+		g_string_append_c (string, '\n');
+	}
+
+	/* Resize string to fit the base64 data. Algorithm from Glib reference */
+	length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7;
+	n_prefix = string->len;
+	g_string_set_size (string, n_prefix + length);
+	
+	/* The actual base64 data */
+	state = save = 0;
+	length = g_base64_encode_step (data, n_data, TRUE, 
+	                               string->str + string->len, &state, &save);
+	g_string_set_size (string, n_prefix + length);
+	
+	/* The suffix */
+	g_string_append_c (string, '\n');
+	g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L);
+	g_string_append (string, g_quark_to_string (type));
+	g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
+	g_string_append_c (string, '\n');
+	
+	*n_result = string->len;
+	return (guchar*)g_string_free (string, FALSE);
+}

Modified: trunk/pkix/gkr-pkix-pem.h
==============================================================================
--- trunk/pkix/gkr-pkix-pem.h	(original)
+++ trunk/pkix/gkr-pkix-pem.h	Mon Jul  7 21:17:26 2008
@@ -29,8 +29,14 @@
 typedef void (*GkrPkixPemCallback) (GQuark type, const guchar *data, gsize n_data,
                                     GHashTable *headers, gpointer user_data);
 
+GHashTable*    gkr_pkix_pem_headers_new       (void);
+
 guint          gkr_pkix_pem_parse             (const guchar *data, gsize n_data, 
                                                GkrPkixPemCallback callback, 
                                                gpointer user_data);
 
+guchar*        gkr_pkix_pem_write             (const guchar *data, gsize n_data, 
+                                               GQuark type, GHashTable *headers,
+                                               gsize *n_result);
+
 #endif /*GKRPKIPEM_H_*/

Modified: trunk/pkix/tests/Makefile.am
==============================================================================
--- trunk/pkix/tests/Makefile.am	(original)
+++ trunk/pkix/tests/Makefile.am	Mon Jul  7 21:17:26 2008
@@ -9,6 +9,7 @@
 	unit-test-gcrypt-setup.c \
 	unit-test-pkix-asn1.c \
 	unit-test-pkix-der.c \
+	unit-test-pkix-openssl.c \
 	unit-test-pkix-parser.c \
 	unit-test-pkix-serialize.c \
 	$(BUILT_SOURCES)

Added: trunk/pkix/tests/unit-test-pkix-openssl.c
==============================================================================
--- (empty file)
+++ trunk/pkix/tests/unit-test-pkix-openssl.c	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,168 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-pkix-openssl.c: Test PKIX openssl
+
+   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 "common/gkr-location.h"
+#include "common/gkr-crypto.h"
+#include "common/gkr-secure-memory.h"
+
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* 
+ * Each test looks like (on one line):
+ *     void unit_test_xxxxx (CuTest* cu)
+ * 
+ * Each setup looks like (on one line):
+ *     void unit_setup_xxxxx (void);
+ * 
+ * Each teardown looks like (on one line):
+ *     void unit_teardown_xxxxx (void);
+ * 
+ * Tests be run in the order specified here.
+ */
+
+static void
+read_file (CuTest *cu, 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);
+	CuAssert (cu, "couldn't read in file", ret);
+	
+	g_free (path);
+}
+
+guchar *refenc = NULL;
+guchar *refdata = NULL;
+gsize n_refenc = 0;
+gsize n_refdata = 0;
+GHashTable *refheaders = NULL;
+
+static void
+copy_each_key_value (gpointer key, gpointer value, gpointer user_data)
+{
+	g_hash_table_insert ((GHashTable*)user_data, g_strdup ((gchar*)key), g_strdup ((gchar*)value));
+}
+
+static void
+parse_reference (GQuark type, const guchar *data, gsize n_data,
+                 GHashTable *headers, gpointer user_data)
+{
+	CuTest *cu = (CuTest*)user_data;
+	GkrPkixResult res;
+	const gchar *dekinfo;
+	
+	CuAssert (cu, "no data in PEM callback", data != NULL);
+	CuAssert (cu, "no data in PEM callback", n_data > 0);
+	refenc = g_memdup (data, n_data);
+	n_refenc = n_data;
+	
+	CuAssert (cu, "no headers present in file", headers != NULL);
+	refheaders = gkr_pkix_pem_headers_new ();
+	g_hash_table_foreach (headers, copy_each_key_value, refheaders);
+	dekinfo = gkr_pkix_openssl_get_dekinfo (headers);
+	CuAssert (cu, "no dekinfo in headers", dekinfo != NULL);
+	
+	res = gkr_pkix_openssl_decrypt_block (dekinfo, "booo", data, n_data, &refdata, &n_refdata);
+	CuAssert (cu, "couldn't openssl decrypt block", res == GKR_PKIX_SUCCESS);
+	CuAssert (cu, "no data returned from openssl decrypt", refdata != NULL);
+	CuAssert (cu, "invalid amount of data returned from openssl decrypt", n_refdata == n_data);
+}
+
+void unit_test_openssl_parse_reference (CuTest* cu)
+{
+	guchar *input;
+	gsize n_input;
+	guint num;
+	
+	read_file (cu, "pem-rsa-enc.key", &input, &n_input);
+
+	num = gkr_pkix_pem_parse (input, n_input, parse_reference, NULL);
+	CuAssert (cu, "couldn't PEM block in reference data", num == 1);
+	
+	CuAssert (cu, "parse_reference() wasn't called", refdata != NULL);
+}
+
+void unit_test_openssl_write_reference (CuTest* cu)
+{
+	const gchar *dekinfo;
+	guchar *encrypted;
+	gsize n_encrypted;
+	gboolean ret;
+	
+	dekinfo = gkr_pkix_openssl_get_dekinfo (refheaders); 
+	CuAssert (cu, "no dekinfo in headers", dekinfo != NULL);
+
+	ret = gkr_pkix_openssl_encrypt_block (dekinfo, "booo", refdata, n_refdata, &encrypted, &n_encrypted);
+	CuAssert (cu, "couldn't openssl encrypt block", ret == TRUE);
+	CuAssert (cu, "no data returned from openssl encrypt", encrypted != NULL);
+	CuAssert (cu, "invalid amount of data returned from openssl encrypt", n_refdata <= n_encrypted);
+	
+	CuAssert (cu, "data length doesn't match input length", n_encrypted == n_refenc);
+	CuAssert (cu, "data doesn't match input", memcmp (encrypted, refenc, n_encrypted) == 0);
+}
+
+/* 29 bytes (prime number, so block length has bad chance of matching */
+const static guchar *TEST_DATA = (guchar*)"ABCDEFGHIJKLMNOPQRSTUVWXYZ123";
+const gsize TEST_DATA_L = 29;
+	
+void unit_test_openssl_roundtrip (CuTest* cu)
+{
+	const gchar *dekinfo;
+	GkrPkixResult res;
+	gboolean ret;
+	guchar *encrypted, *decrypted;
+	gsize n_encrypted, n_decrypted;
+	int i;
+	
+	dekinfo = gkr_pkix_openssl_prep_dekinfo (refheaders);
+	
+	ret = gkr_pkix_openssl_encrypt_block (dekinfo, "password", TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted);
+	CuAssert (cu, "couldn't openssl encrypt block", ret == TRUE);
+	CuAssert (cu, "no data returned from openssl encrypt", encrypted != NULL);
+	CuAssert (cu, "invalid amount of data returned from openssl encrypt", TEST_DATA_L <= n_encrypted);
+
+	res = gkr_pkix_openssl_decrypt_block (dekinfo, "password", encrypted, n_encrypted, &decrypted, &n_decrypted);
+	CuAssert (cu, "couldn't openssl decrypt block", res == GKR_PKIX_SUCCESS);
+	CuAssert (cu, "no data returned from openssl decrypt", decrypted != NULL);
+
+	/* Check that the data was decrypted properly */
+	CuAssert (cu, "decrypted data doesn't match length", n_decrypted >= TEST_DATA_L);
+	CuAssert (cu, "decrypted data doesn't match", memcmp (TEST_DATA, decrypted, TEST_DATA_L) == 0);
+	
+	/* Check that the remainder is all zeros */
+	for (i = TEST_DATA_L; i < n_decrypted; ++i)
+		CuAssert (cu, "non null byte in padding", decrypted[i] == 0);
+}

Modified: trunk/pkix/tests/unit-test-pkix-parser.c
==============================================================================
--- trunk/pkix/tests/unit-test-pkix-parser.c	(original)
+++ trunk/pkix/tests/unit-test-pkix-parser.c	Mon Jul  7 21:17:26 2008
@@ -125,30 +125,43 @@
 	return TRUE;
 }
 
-static gchar*
+static gboolean
 ask_password (GkrPkixParser *parser, GQuark loc, gkrconstid digest, 
-              GQuark type, const gchar *details, guint n_prompts, 
-              gpointer user_data) 
+              GQuark type, const gchar *details, gint *state, 
+              gchar **password, gpointer user_data) 
 {
 	CuTest *cu = the_cu;
-	g_assert (cu);
-
 	gchar *msg;
+	gint st;
 	
-	/* Should only be asking once per location */
-	if (n_prompts > 0) {
-		msg = g_strdup_printf ("decryption didn't work for: %s", g_quark_to_string (loc));
-		CuAssert (cu, msg, FALSE);
-		return NULL;
-	}
-	
+	g_assert (cu);
+	CuAssert (cu, "state is null", state != NULL);
+	CuAssert (cu, "state is bad", *state >= 0 && *state < 3);
+
+	st = *state;
+	(*state)++;
+
 	CuAssert (cu, "location is empty", loc != 0);
 	CuAssert (cu, "details is null", details != NULL);
 	
-	g_print ("getting password 'booo' for: %s\n", details); 	
-	
-	/* All our test encrypted stuff use this password */
-	return gkr_secure_strdup ("booo");
+	/* Return "", null, and "booo" in that order */
+	switch (st) {
+	case 0:
+		*password = gkr_secure_strdup ("");
+		return TRUE;
+	case 1:
+		*password = NULL;
+		return TRUE;
+	case 2:
+		/* Most of our test encrypted stuff use this password */
+		g_print ("getting password 'booo' for: %s\n", details); 	
+		*password = gkr_secure_strdup ("booo");
+		return TRUE;
+	default:
+		msg = g_strdup_printf ("decryption didn't work for: %s", g_quark_to_string (loc));
+		CuAssert (cu, msg, FALSE);
+		return FALSE;
+	};
 }
 
 static void

Modified: trunk/pkix/tests/unit-test-pkix-serialize.c
==============================================================================
--- trunk/pkix/tests/unit-test-pkix-serialize.c	(original)
+++ trunk/pkix/tests/unit-test-pkix-serialize.c	Mon Jul  7 21:17:26 2008
@@ -67,28 +67,31 @@
 	g_free (path);
 }
 
-static gchar*
+static gboolean
 ask_password (GkrPkixParser *parser, GQuark loc, gkrconstid unique, 
-              GQuark type, const gchar *details, guint n_prompts, 
-              gpointer user_data) 
+              GQuark type, const gchar *details, gint *state, 
+              gchar **password, gpointer user_data) 
 {
 	CuTest *cu = (CuTest*)user_data;
 	gchar *msg;
 	
 	/* Should only be asking once per location */
-	if (n_prompts > 0) {
+	if (*state > 0) {
 		msg = g_strdup_printf ("decryption didn't work for: %s", g_quark_to_string (loc));
 		CuAssert (cu, msg, FALSE);
-		return NULL;
+		return FALSE;
 	}
 	
+	(*state)++;
+	
 	CuAssert (cu, "type is zero", type != 0);
 	CuAssert (cu, "details is null", details != NULL);
 	
 	g_print ("getting password 'booo' for: %s\n", details); 	
 	
 	/* All our test encrypted stuff use this password */
-	return gkr_secure_strdup ("booo");
+	*password = gkr_secure_strdup ("booo");
+	return TRUE;
 }
 
 void unit_test_serialize_certificate (CuTest* cu)

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Mon Jul  7 21:17:26 2008
@@ -5,7 +5,10 @@
 data/gnome-keyring.schemas.in
 library/gnome-keyring-utils.c
 keyrings/gkr-keyring-login.c
-pk/gkr-pk-object-storage.c
+keyrings/gkr-keyring.c
+pk/gkr-pk-index.c
+pk/gkr-pk-storage.c
 pkix/gkr-pkix-parser.c
 pkix/gkr-pkix-serialize.c
+ssh/gkr-ssh-storage.c
 ui/gkr-ask-tool.c

Modified: trunk/reference/tmpl/gnome-keyring-item-info.sgml
==============================================================================
--- trunk/reference/tmpl/gnome-keyring-item-info.sgml	(original)
+++ trunk/reference/tmpl/gnome-keyring-item-info.sgml	Mon Jul  7 21:17:26 2008
@@ -26,6 +26,7 @@
 @GNOME_KEYRING_ITEM_NOTE: 
 @GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD: 
 @GNOME_KEYRING_ITEM_ENCRYPTION_KEY_PASSWORD: 
+ GNOME_KEYRING_ITEM_PK_STORAGE: 
 @GNOME_KEYRING_ITEM_LAST_TYPE: 
 
 <!-- ##### TYPEDEF GnomeKeyringItemInfo ##### -->

Modified: trunk/ssh/Makefile.am
==============================================================================
--- trunk/ssh/Makefile.am	(original)
+++ trunk/ssh/Makefile.am	Mon Jul  7 21:17:26 2008
@@ -16,8 +16,17 @@
 	gkr-ssh-daemon-io.c \
 	gkr-ssh-daemon-ops.c \
 	gkr-ssh-private.h \
-	gkr-ssh-proto.c
+	gkr-ssh-proto.c \
+	gkr-ssh-storage.c gkr-ssh-storage.h 
 
 libgkr_ssh_la_LIBADD = \
 	$(GLIB_LIBS) \
 	$(GOBJECT_LIBS)
+
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR = 
+endif
+
+SUBDIRS = . $(TESTS_DIR)

Modified: trunk/ssh/gkr-ssh-daemon-io.c
==============================================================================
--- trunk/ssh/gkr-ssh-daemon-io.c	(original)
+++ trunk/ssh/gkr-ssh-daemon-io.c	Mon Jul  7 21:17:26 2008
@@ -42,7 +42,7 @@
 #include "common/gkr-daemon-util.h"
 #include "common/gkr-secure-memory.h"
 
-#include "pk/gkr-pk-object-storage.h"
+#include "pk/gkr-pk-storage.h"
 
 #ifndef HAVE_SOCKLEN_T
 #define socklen_t int
@@ -175,7 +175,7 @@
 	gkr_async_register_cancel (close_fd, &client->sock);
 	
 	/* Make sure everything is in sync for this connection */
-	gkr_pk_object_storage_refresh (NULL);
+	gkr_pk_storage_refresh_all ();
 	
 	while (!gkr_async_is_stopping ()) {
 		

Modified: trunk/ssh/gkr-ssh-daemon-ops.c
==============================================================================
--- trunk/ssh/gkr-ssh-daemon-ops.c	(original)
+++ trunk/ssh/gkr-ssh-daemon-ops.c	Mon Jul  7 21:17:26 2008
@@ -264,6 +264,7 @@
 {
 	GList *objects, *pubkeys, *l;
 	GkrPkPubkey *pub;
+	gsize blobpos;
 	const gchar *label;
 	
 	/* Only find the keys that have usage = ssh */
@@ -285,10 +286,17 @@
 		pub = GKR_PK_PUBKEY (l->data);
 		g_return_val_if_fail (GKR_IS_PK_PUBKEY (pub), FALSE);
 		
+		/* Add a space for the key blob length */		
+		blobpos = resp->len;
+		gkr_buffer_add_uint32 (resp, 0);
+		
 		if (!gkr_ssh_proto_write_public (resp, gkr_pk_pubkey_get_algorithm (pub),
 		                                 gkr_pk_pubkey_get_key (pub)))
 			return FALSE;
 		
+		/* Write back the blob length */
+		gkr_buffer_set_uint32 (resp, blobpos, (resp->len - blobpos) - 4);
+		
 		/* And now a per key comment */
 		label = gkr_pk_object_get_label (GKR_PK_OBJECT (pub));
 		gkr_buffer_add_string (resp, label ? label : "");
@@ -387,12 +395,18 @@
 	gsize offset;
 	gcry_error_t gcry;
 	gboolean ret;
-	guint blobpos;
+	guint blobpos, sz;
 	guchar *hash;
 	int algo;
 	int halgo, n_algo;
 	
 	offset = 5;
+	
+	/* The key packet size */
+	if (!gkr_buffer_get_uint32 (req, offset, &offset, &sz))
+		return FALSE;
+
+	/* The key itself */
 	if (!gkr_ssh_proto_read_public (req, &offset, &s_key, &algo))
 		return FALSE;
 		
@@ -624,8 +638,15 @@
 	GkrPkObject *obj;
 	gcry_sexp_t skey;
 	gsize offset;
+	guint sz;
 	
 	offset = 5;
+	
+	/* The key packet size */
+	if (!gkr_buffer_get_uint32 (req, offset, &offset, &sz))
+		return FALSE;
+
+	/* The public key itself */
 	if (!gkr_ssh_proto_read_public (req, &offset, &skey, NULL))
 		return FALSE;
 	

Modified: trunk/ssh/gkr-ssh-proto.c
==============================================================================
--- trunk/ssh/gkr-ssh-proto.c	(original)
+++ trunk/ssh/gkr-ssh-proto.c	Mon Jul  7 21:17:26 2008
@@ -161,13 +161,8 @@
 {
 	gboolean ret;
 	gchar *stype;
-	guint sz;
 	int alg;
 	
-	/* The key packet size */
-	if (!gkr_buffer_get_uint32 (req, *offset, offset, &sz))
-		return FALSE;
-	
 	/* The string algorithm */
 	if (!gkr_buffer_get_string (req, *offset, offset, &stype, (GkrBufferAllocator)g_realloc))
 		return FALSE;
@@ -425,13 +420,8 @@
 gkr_ssh_proto_write_public (GkrBuffer *resp, int algo, gcry_sexp_t key)
 {
 	gboolean ret = FALSE;
-	gsize blobpos;
 	const gchar *salgo;
 	
-	/* Add a space for the key blob length */		
-	blobpos = resp->len;
-	gkr_buffer_add_uint32 (resp, 0);
-
 	salgo = gkr_ssh_proto_algo_to_keytype (algo);
 	g_assert (salgo);
 	gkr_buffer_add_string (resp, salgo);
@@ -449,9 +439,6 @@
 		g_return_val_if_reached (FALSE);
 		break;
 	}
-		
-	/* Write back the blob length */
-	gkr_buffer_set_uint32 (resp, blobpos, (resp->len - blobpos) - 4);
 
 	return ret;
 }

Added: trunk/ssh/gkr-ssh-storage.c
==============================================================================
--- (empty file)
+++ trunk/ssh/gkr-ssh-storage.c	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,934 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-ssh-storage.c - Storage of SSH keys
+
+   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 "gkr-ssh-private.h"
+#include "gkr-ssh-storage.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-crypto.h"
+#include "common/gkr-location.h"
+#include "common/gkr-location-watch.h"
+#include "common/gkr-secure-memory.h"
+
+#include "keyrings/gkr-keyring-login.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "pk/gkr-pk-privkey.h"
+#include "pk/gkr-pk-object-manager.h"
+#include "pk/gkr-pk-util.h"
+
+#include "pkix/gkr-pkix-asn1.h"
+#include "pkix/gkr-pkix-der.h"
+#include "pkix/gkr-pkix-openssl.h"
+#include "pkix/gkr-pkix-pem.h"
+#include "pkix/gkr-pkix-types.h"
+
+#include "ui/gkr-ask-daemon.h"
+#include "ui/gkr-ask-request.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdarg.h>
+
+typedef struct _GkrSshStoragePrivate GkrSshStoragePrivate;
+
+struct _GkrSshStoragePrivate {
+	gkrid specific_load_request;
+	GQuark home_location;
+	GkrPkIndex *index;
+	GkrLocationWatch *watch;
+};
+
+#define GKR_SSH_STORAGE_GET_PRIVATE(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GKR_TYPE_SSH_STORAGE, GkrSshStoragePrivate))
+
+G_DEFINE_TYPE(GkrSshStorage, gkr_ssh_storage, GKR_TYPE_PK_STORAGE);
+
+static GQuark PEM_RSA_PRIVATE_KEY;
+static GQuark PEM_DSA_PRIVATE_KEY;
+
+#define NO_VALUE GUINT_TO_POINTER (TRUE)
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static GQuark
+location_for_storing_private_key (GkrSshStorage *storage, gcry_sexp_t sexp)
+{
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+	const gchar *pref;
+	gchar *name;
+	GQuark loc = 0;
+	int algo, i;
+	
+	/* What kind of key is it? */
+	algo = gkr_crypto_skey_parse (sexp, &algo, NULL, NULL);
+	switch (algo) {
+	case GCRY_PK_RSA:
+		pref = "id_rsa";
+		break;
+	case GCRY_PK_DSA:
+		pref = "id_dsa";
+		break;
+	default:
+		pref = "id_xsa";
+		break;
+	};
+	
+	/* Find a file that's unique */
+	for (i = 0; i < ~0; i++) {
+		name = (i == 0) ? g_strdup (pref) : g_strdup_printf ("%s.%d", pref, i);
+		loc = gkr_location_from_child (pv->home_location, name);
+		if (!gkr_location_test_file(loc, G_FILE_TEST_EXISTS))
+			break;
+		g_free (name);
+		loc = 0;
+	}
+
+	return loc;
+}
+
+static GkrPkObject*
+prepare_object (GkrSshStorage *storage, GQuark location, 
+                gkrconstid digest, gboolean is_public)
+{
+	GkrPkObjectManager *manager;
+	GkrPkObject *object;
+	GType gtype;
+	
+	manager = gkr_pk_object_manager_for_token ();
+	object = gkr_pk_object_manager_find_by_digest (manager, digest);
+	
+	/* The object already exists just reference it */
+	if (object) {
+		gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+		return object;
+	} 
+	
+	if (is_public)
+		gtype = GKR_TYPE_PK_PUBKEY;
+	else
+		gtype = GKR_TYPE_PK_PRIVKEY;
+	
+	object = g_object_new (gtype, "manager", manager, "location", location, 
+	                       "digest", digest, NULL);
+	gkr_pk_storage_add_object (GKR_PK_STORAGE (storage), object);
+
+	/* Object was reffed */
+	g_object_unref (object);
+	return object;
+}
+
+static GQuark
+public_location_for_private (GQuark loc)
+{
+	gchar *pstr;
+	GQuark ploc;
+	
+	pstr = g_strdup_printf ("%s.pub", gkr_location_to_string (loc));
+	ploc = gkr_location_from_string (pstr);
+	g_free (pstr);
+	
+	return ploc;
+}
+
+static gboolean
+storage_load_public_key (GkrSshStorage *storage, GQuark loc, GError **err)
+{
+ 	GkrPkObject *object;
+	GkrPkixResult res;
+	gcry_sexp_t sexp;
+	gkrid digest;
+	gchar *comment;
+	guchar *data;
+	gsize n_data;
+	
+	g_return_val_if_fail (loc, FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
+	if (!gkr_location_read_file (loc, &data, &n_data, err))
+		return FALSE;
+
+	res = gkr_ssh_storage_load_public_key (data, n_data, &sexp, &comment);
+	if (res == GKR_PKIX_FAILURE) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Couldn't read secure shell key public key: %s"),
+		             g_quark_to_string (loc));
+		return FALSE;
+	} else if (res == GKR_PKIX_UNRECOGNIZED) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Invalid secure shell public key at: %s"),
+		             g_quark_to_string (loc));
+		return FALSE;
+	}
+	
+	digest = gkr_id_new_digest (data, n_data);
+	
+	/* Prepare and setup the object */
+	object = prepare_object (storage, loc, digest, TRUE);
+	g_object_set (object, "orig-label", comment, NULL);
+	g_object_set (object, "gcrypt-sexp", sexp, NULL);
+	
+	
+	gkr_id_free (digest);
+	g_free (comment);
+	return TRUE;
+}
+
+static gboolean
+storage_write_public_key (GkrSshStorage *storage, gcry_sexp_t sexp, 
+                          GQuark loc, GError **err)
+{
+	guchar *data;
+	gsize n_data;
+	gboolean ret;
+	
+	g_return_val_if_fail (loc, FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+
+	/* TODO: What about the comment? */
+	data = gkr_ssh_storage_write_public_key(sexp, NULL, &n_data); 
+	if (!data) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Couldn't encode secure shell public key."));
+		return FALSE;
+	}
+	
+	/* And write that to disk */ 
+	ret = gkr_location_write_file (loc, data, n_data, err);
+	g_free (data);
+	return ret;
+}
+
+static gboolean
+store_public_key_for_private (GkrSshStorage *storage, GkrPkObject *priv, GError **err)
+{
+	gcry_sexp_t sexp, psexp;
+	gboolean ret;
+	GQuark ploc;
+	
+	g_return_val_if_fail (GKR_IS_PK_PRIVKEY (priv), FALSE);
+	g_return_val_if_fail (priv->location, FALSE);
+
+	/* Don't have a key to write out :( */
+	g_object_get (priv, "gcrypt-sexp", &sexp, NULL);
+	if (!sexp)
+		return TRUE;
+	
+	/* Convert to a public key */
+	if (!gkr_crypto_skey_private_to_public (sexp, &psexp))
+		g_return_val_if_reached (FALSE);
+	
+	/* And then store that public key next to the private */
+	ploc = public_location_for_private (priv->location);
+	ret = storage_write_public_key (storage, psexp, ploc, err);
+	gcry_sexp_release (psexp);
+	
+	return ret;
+}
+
+static GkrPkixResult 
+load_encrypted_key (GkrSshStorage *storage, gkrid digest, GQuark location, 
+                    const gchar *dekinfo, const guchar *data, gsize n_data, 
+                    gcry_sexp_t *skey)
+{
+	GkrPkixResult ret;
+	gchar *password;
+	guchar *decrypted;
+	gsize n_decrypted;
+	gboolean res;
+	gint l, state;
+	
+	state = GKR_PK_STORAGE_PASSWD_STATE;
+	while (!gkr_async_is_stopping ()) {
+
+		/* Get the password to try */
+		if (!gkr_pk_storage_get_load_password (GKR_PK_STORAGE (storage), location,
+		                                       digest, GKR_PKIX_PRIVATE_KEY, NULL, 
+		                                       &state, &password))
+			return GKR_PKIX_SUCCESS;
+
+		decrypted = NULL;
+		n_decrypted = 0;
+		
+		/* Decrypt, this will result in garble if invalid password */	
+		res = gkr_pkix_openssl_decrypt_block (dekinfo, password, data, n_data, 
+		                                      &decrypted, &n_decrypted);
+		gkr_secure_free (password);
+		
+		if (!res)
+			return GKR_PKIX_UNRECOGNIZED;
+			
+		g_assert (decrypted);
+		
+		/* Unpad the DER data */
+		l = gkr_pkix_asn1_element_length (decrypted, n_decrypted);
+		if (l > 0)
+			n_decrypted = l;
+	
+		/* Try to parse */
+		ret = gkr_pkix_der_read_private_key (decrypted, n_decrypted, skey);
+		gkr_secure_free (decrypted);
+
+		if (ret != GKR_PKIX_UNRECOGNIZED)
+			return ret;
+	}
+	
+	return GKR_PKIX_FAILURE;
+}
+
+
+static void
+add_corresponding_public (GkrSshStorage *storage, GQuark loc)
+{
+	GError *err = NULL;
+	GQuark ploc;
+	
+	g_return_if_fail (loc);
+	ploc = public_location_for_private (loc);
+	
+	if (gkr_location_test_file (ploc, G_FILE_TEST_IS_REGULAR)) {
+		if (!storage_load_public_key (storage, ploc, &err)) {
+			g_message ("couldn't parse public key: %s: %s", g_quark_to_string (ploc),
+			           err && err->message ? err->message : "");
+			g_clear_error (&err);
+		}
+	}
+}
+
+typedef struct _Load {
+	GkrSshStorage *storage;
+	GQuark location;
+	gboolean seen;
+	GkrPkixResult result;
+} Load;
+
+static void
+parsed_pem_block (GQuark type, const guchar *data, gsize n_data,
+                  GHashTable *headers, gpointer user_data)
+{
+	Load *ctx = (Load*)user_data;
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (ctx->storage);
+	gcry_sexp_t sexp;
+	GkrPkObject *object;
+	const gchar *dekinfo;
+	gkrid digest;
+	
+	/* Only handle SSHv2 private keys */
+	if (type != PEM_RSA_PRIVATE_KEY && type != PEM_DSA_PRIVATE_KEY)
+		return;
+	
+	/* Only parse first key in the file */
+	if (ctx->seen)
+		return;
+	
+	digest = gkr_id_new_digest (data, n_data);
+	ctx->seen = TRUE;
+	
+	/* If it's encrypted ... */
+	dekinfo = gkr_pkix_openssl_get_dekinfo (headers);
+	if (dekinfo) {
+		/* This key was specifically requested to be loaded */
+		if (gkr_id_equals (digest, pv->specific_load_request)) {
+			ctx->result = load_encrypted_key (ctx->storage, digest, ctx->location, 
+			                                  dekinfo, data, n_data, &sexp);
+			
+		/* Nobody's asking us to load this key just yet */
+		} else {
+			ctx->result = GKR_PKIX_SUCCESS;
+			sexp = NULL;
+		}
+		
+	/* not encryted, just load the data */
+	} else {
+		ctx->result = gkr_pkix_der_read_private_key (data, n_data, &sexp);
+	}
+	
+	if (ctx->result == GKR_PKIX_SUCCESS) {
+		if (gkr_id_equals (pv->specific_load_request, digest))
+			pv->specific_load_request = NULL;
+	
+		/* Prepare and setup the object */
+		object = prepare_object (ctx->storage, ctx->location, digest, FALSE);
+		if (sexp)
+			g_object_set (object, "gcrypt-sexp", sexp, NULL);
+	
+		gkr_id_free (digest);
+	}
+}
+
+static gboolean
+storage_load_private_key (GkrSshStorage *storage, GQuark loc, GError **err)
+{
+	Load ctx;
+	guchar *data;
+	gsize n_data;
+	guint num;
+	
+	g_return_val_if_fail (loc, FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
+	if (!gkr_location_read_file (loc, &data, &n_data, err))
+		return FALSE;
+
+	memset (&ctx, 0, sizeof (ctx));
+	ctx.storage = storage;
+	ctx.location = loc;
+
+	num = gkr_pkix_pem_parse (data, n_data, parsed_pem_block, &ctx);
+	
+	/* Didn't find any private key there */
+	if (num == 0) 
+		return TRUE;
+	
+	if (ctx.result == GKR_PKIX_FAILURE) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Couldn't read secure shell key private key: %s"),
+		             g_quark_to_string (loc));
+		return FALSE;
+	} else if (ctx.result == GKR_PKIX_UNRECOGNIZED) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, _("Invalid secure shell private key at: %s"),
+		             g_quark_to_string (loc));
+		return FALSE;
+	}
+	
+	/* Load the corresponding public key */
+	add_corresponding_public (storage, loc);
+	
+	return TRUE;
+}
+
+static gkrid
+storage_write_private_key (GkrSshStorage *storage, gcry_sexp_t sexp, 
+                           GQuark loc, const gchar *password, GError **err)
+{
+	GHashTable *headers;
+	const gchar *dekinfo;
+	GQuark type;
+	guchar *data, *encrypted, *result;
+	gsize n_data, n_encrypted, n_result;
+	gboolean is_priv;
+	gkrid digest = NULL;
+	int algo;
+	
+	data = encrypted = result = NULL;
+	headers = NULL;
+	
+	/* What kind of key is it? */
+	algo = gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL);
+	g_return_val_if_fail (is_priv == TRUE, NULL);
+	g_return_val_if_fail (algo != 0, NULL);
+
+	/* Figure out what kind of BEGIN/END PEM we need */
+	if (algo == GCRY_PK_RSA)
+		type = PEM_RSA_PRIVATE_KEY;
+	else if (algo == GCRY_PK_DSA)
+		type = PEM_DSA_PRIVATE_KEY;
+	else
+		g_return_val_if_reached (NULL); 
+
+	/* Write out the raw key to memory */
+	data = gkr_pkix_der_write_private_key (sexp, &n_data);
+	g_return_val_if_fail (data, NULL);
+
+	/* Write an encrypted private key */
+	if (password) {
+		headers = gkr_pkix_pem_headers_new ();
+		dekinfo = gkr_pkix_openssl_prep_dekinfo (headers);
+
+		if (!gkr_pkix_openssl_encrypt_block (dekinfo, password, data, n_data,
+		                                     &encrypted, &n_encrypted)) {
+			g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, 
+			             _("Couldn't encrypt the SSH key to store it."));
+			goto done;
+		}
+		digest = gkr_id_new_digest (encrypted, n_encrypted);
+		result = gkr_pkix_pem_write (encrypted, n_encrypted, type, headers, &n_result);
+		g_free (encrypted);
+		
+	/* Write a non-encrypted private key */
+	} else {
+		digest = gkr_id_new_digest (data, n_data);
+		result = gkr_pkix_pem_write (data, n_data, type, headers, &n_result);
+	}
+	
+	/* Make sure it worked */
+	if (!result) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, 
+		             _("Couldn't encode the SSH key to store it."));
+		gkr_id_free (digest);
+		digest = NULL;
+		goto done;
+	}
+	
+	/* Now write it to the file */
+	if (gkr_location_write_file (loc, result, n_result, err)) {
+		gkr_id_free (digest);
+		digest = NULL;
+	}
+
+done:
+	if (headers)
+		g_hash_table_destroy (headers);
+	gkr_secure_free (data);
+	g_free (result);
+	g_free (encrypted);
+	
+	return digest;
+}
+
+static void
+location_load (GkrLocationWatch *watch, GQuark loc, GkrSshStorage *storage)
+{
+	GError *err = NULL;
+
+	/* We only get notified for private keys */
+	if (!storage_load_private_key (storage, loc, &err)) {
+		g_message ("couldn't parse data: %s: %s", g_quark_to_string (loc),
+		           err && err->message ? err->message : "");
+		g_clear_error (&err);
+	}
+}
+
+static void
+location_remove (GkrLocationWatch *watch, GQuark loc, GkrSshStorage *storage)
+{
+	/* Remove key that is at that location */
+ 	gkr_pk_storage_clr_objects (GKR_PK_STORAGE (storage), loc);
+
+ 	/* We only watch private keys, so try and clear out the public */
+	gkr_pk_storage_clr_objects (GKR_PK_STORAGE (storage), 
+	                            public_location_for_private (loc));
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void 
+gkr_ssh_storage_refresh (GkrPkStorage *storage)
+{
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ 	gkr_location_watch_refresh (pv->watch, FALSE);
+}
+
+static gboolean 
+gkr_ssh_storage_load (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+	gboolean ret = FALSE;
+		
+	g_return_val_if_fail (GKR_IS_PK_OBJECT (obj), FALSE);
+	g_return_val_if_fail (obj->storage == storage, FALSE);
+	g_return_val_if_fail (obj->location, FALSE);
+	g_return_val_if_fail (pv->specific_load_request == NULL, FALSE);
+	
+	g_object_ref (obj);
+
+	/* Make note of the specific load request */
+	pv->specific_load_request = obj->digest;
+	
+	/* Load a private key from this location */
+	if (GKR_IS_PK_PRIVKEY (obj))
+		storage_load_private_key (GKR_SSH_STORAGE (storage), obj->location, err);
+	
+	/* Load a private key from this location */
+	else if (GKR_IS_PK_PUBKEY (obj))
+		storage_load_public_key (GKR_SSH_STORAGE (storage), obj->location, err);
+	
+	else
+		g_return_val_if_reached (FALSE);
+	
+	/* See if it was seen */
+	if (pv->specific_load_request != NULL) {
+		g_set_error (err, GKR_SSH_STORAGE_ERROR, 0, "The object was not found at: %s",
+		             g_quark_to_string (obj->location));
+		pv->specific_load_request = NULL;
+		goto done;
+	}
+	
+	/* 
+	 * At this point, if we were loading a public key, it should be all loaded, 
+	 * including encrypted parts. Write out the public key if needed. 
+	 */
+	if (GKR_IS_PK_PRIVKEY (obj))
+		store_public_key_for_private (GKR_SSH_STORAGE (storage), obj, NULL);
+
+	ret = TRUE;
+
+done:
+	g_object_unref (obj);
+	return ret;
+}
+
+static gboolean 
+gkr_ssh_storage_store (GkrPkStorage *stor, GkrPkObject *obj, GError **err)
+{
+	GkrSshStorage *storage;
+	gcry_sexp_t sexp;
+	gchar *password;
+	gchar *label;
+	gkrid digest;
+	gboolean save, ret;
+	GQuark loc;
+	
+	g_return_val_if_fail (!err || !*err, FALSE);
+	g_return_val_if_fail (GKR_IS_SSH_STORAGE (stor), FALSE);
+	g_return_val_if_fail (obj->storage == NULL, FALSE);
+	g_return_val_if_fail (obj->location == 0, FALSE);
+	
+	storage = GKR_SSH_STORAGE (stor);
+	
+	/* We don't yet support storing arbitrary public keys */
+	if (GKR_IS_PK_PUBKEY (obj))
+		return TRUE;
+	
+	g_return_val_if_fail (GKR_IS_PK_PRIVKEY (obj), FALSE);
+	
+	/* Pull out the actual part of the key */
+	g_object_get (obj, "gcrypt-sexp", &sexp, NULL);
+	g_return_val_if_fail (sexp, FALSE);
+
+	/* Find a good location to store this key */
+	loc = location_for_storing_private_key (storage, sexp);
+	g_return_val_if_fail (loc, FALSE);
+		
+	/* Get a password for this key, determines whether encrypted or not */
+	label = gkr_pk_object_get_label (obj);
+	ret = gkr_pk_storage_get_store_password (stor, loc, GKR_PKIX_PRIVATE_KEY, 
+	                                         label, &save, &password);
+	g_free (label);
+	
+	/* Prompt for a password was denied */
+	if (!ret)
+		return TRUE;
+		
+	/* Store the private key */
+	digest = storage_write_private_key (storage, sexp, loc, password, err);
+	gkr_secure_strfree (password);
+	
+	if (!digest)
+		return FALSE;
+	
+	/* The object now has a (possibly new) location */
+	g_object_set (obj, "location", loc, "storage", stor, "digest", digest, NULL);
+	gkr_id_free (digest);
+	
+	/* Now store the public key in place if possible */
+	return store_public_key_for_private (storage, obj, err);
+}
+
+static gboolean 
+gkr_ssh_storage_remove (GkrPkStorage *storage, GkrPkObject *obj, GError **err)
+{
+	GQuark ploc;
+	
+	g_return_val_if_fail (!err || !*err, FALSE);
+	g_return_val_if_fail (GKR_IS_SSH_STORAGE (storage), FALSE);
+	g_return_val_if_fail (obj->storage == storage, FALSE);
+	g_return_val_if_fail (obj->location, FALSE);
+	
+	/* Delete the public key along with the private */
+	if (GKR_IS_PK_PRIVKEY (obj)) {
+		ploc = public_location_for_private (obj->location);
+		if (!gkr_location_delete_file (ploc, err))
+			return FALSE;
+	}
+	
+	/* Delete the object itself */
+	if (!gkr_location_delete_file (obj->location, err))
+		return FALSE;
+	
+	gkr_ssh_storage_refresh (storage);
+	return TRUE;
+}
+
+static GkrPkIndex* 
+gkr_ssh_storage_index (GkrPkStorage *storage, GQuark unused)
+{
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ 	GnomeKeyringAttributeList *attrs;
+	GQuark kloc;
+	
+	if (!pv->index) {
+		/* We default to a keyring stored on the computer */
+		kloc = gkr_location_from_child (GKR_LOCATION_VOLUME_LOCAL, 
+		                                "pk-storage.keyring");
+		
+		/* Default attributes for our index */
+		attrs = gnome_keyring_attribute_list_new ();
+		gnome_keyring_attribute_list_append_string (attrs, "purposes", "ssh-authentication");
+		
+		pv->index = gkr_pk_index_open (kloc, "pk-storage", attrs);
+		gnome_keyring_attribute_list_free (attrs);
+		
+		g_return_val_if_fail (pv->index, NULL);
+	}
+	
+	return pv->index;
+}
+
+
+static void
+gkr_ssh_storage_init (GkrSshStorage *storage)
+{
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (storage);
+ 	
+	pv->specific_load_request = NULL;
+	pv->home_location = gkr_location_from_child (GKR_LOCATION_VOLUME_HOME, ".ssh/");
+	
+	/* Watch all ~/.ssh/id_?sa* except for *.pub files */
+	pv->watch = gkr_location_watch_new (NULL, GKR_LOCATION_VOLUME_HOME, ".ssh", 
+	                                    "id_?sa*", "*.pub");
+	g_return_if_fail (pv->watch); 
+
+	g_signal_connect (pv->watch, "location-added", G_CALLBACK (location_load), storage);
+	g_signal_connect (pv->watch, "location-changed", G_CALLBACK (location_load), storage);
+	g_signal_connect (pv->watch, "location-removed", G_CALLBACK (location_remove), storage);
+}
+
+static void
+gkr_ssh_storage_dispose (GObject *obj)
+{
+	GkrSshStorage *storage = GKR_SSH_STORAGE (obj);
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (obj);
+ 	
+	g_signal_handlers_disconnect_by_func (pv->watch, location_load, storage);
+	g_signal_handlers_disconnect_by_func (pv->watch, location_remove, storage);
+	
+	if (pv->index)
+		g_object_unref (pv->index);
+	pv->index = NULL;
+ 	
+	G_OBJECT_CLASS (gkr_ssh_storage_parent_class)->dispose (obj);
+}
+
+static void
+gkr_ssh_storage_finalize (GObject *obj)
+{
+ 	GkrSshStoragePrivate *pv = GKR_SSH_STORAGE_GET_PRIVATE (obj);
+ 	
+	g_object_unref (pv->watch);
+ 	pv->watch = NULL;
+ 	
+ 	g_assert (pv->index == NULL);
+	
+	G_OBJECT_CLASS (gkr_ssh_storage_parent_class)->finalize (obj);
+}
+
+static void
+gkr_ssh_storage_class_init (GkrSshStorageClass *klass)
+{
+	GkrPkStorageClass *storage_class = GKR_PK_STORAGE_CLASS (klass);
+	GObjectClass *gobject_class;
+	
+	gobject_class = (GObjectClass*)klass;
+	gobject_class->dispose = gkr_ssh_storage_dispose;
+	gobject_class->finalize = gkr_ssh_storage_finalize;
+
+	storage_class->refresh = gkr_ssh_storage_refresh;
+	storage_class->load = gkr_ssh_storage_load;
+	storage_class->store = gkr_ssh_storage_store;
+	storage_class->remove = gkr_ssh_storage_remove;
+	storage_class->index = gkr_ssh_storage_index;
+	
+	gkr_ssh_storage_parent_class = g_type_class_peek_parent (klass);
+
+	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_type_class_add_private (gobject_class, sizeof (GkrSshStoragePrivate));
+}
+
+/* -------------------------------------------------------------------------------
+ * PUBLIC FUNCTIONS
+ */
+
+GQuark
+gkr_ssh_storage_get_error_domain (void)
+{
+	static GQuark domain = 0;
+	if (domain == 0)
+		domain = g_quark_from_static_string ("gkr-ssh-storage-error");
+	return domain;
+}
+
+gboolean
+gkr_ssh_storage_initialize (void)
+{
+	GkrPkStorage *storage;
+	
+	storage = g_object_new (GKR_TYPE_SSH_STORAGE, NULL);
+	gkr_pk_storage_register (storage, FALSE);
+	g_object_unref (storage);
+	
+	return TRUE;
+}
+
+GkrPkixResult
+gkr_ssh_storage_load_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, GKR_PKIX_FAILURE);
+	g_return_val_if_fail (sexp, GKR_PKIX_FAILURE);
+	
+	/* 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 GKR_PKIX_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 GKR_PKIX_UNRECOGNIZED;
+	}
+	
+	/* Parse the key type */
+	val = g_strndup ((gchar*)data, at - data);
+	algo = gkr_ssh_proto_keytype_to_algo (val);
+	if (!algo) 
+		g_message ("Unsupported or unknown SSH key algorithm: %s", val);
+	g_free (val);
+	if (!algo)
+		return GKR_PKIX_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 = gkr_ssh_proto_read_public (&buf, &offset, sexp, NULL);
+	g_free (decoded);
+	if (!ret) {
+		g_message ("failed to parse base64 part of SSH key");
+		return GKR_PKIX_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 && n_data)
+		*comment = g_strndup ((gchar*)data, n_data);
+
+	return GKR_PKIX_SUCCESS;
+}
+
+guchar*
+gkr_ssh_storage_write_public_key (gcry_sexp_t sexp, gchar *comment,
+                                  gsize *n_data)
+{
+	GString *result;
+	GkrBuffer buffer;
+	const gchar *type;
+	gchar *encoded;
+	gboolean is_priv;
+	int algo;
+	
+	g_return_val_if_fail (n_data, NULL);
+	g_return_val_if_fail (sexp, NULL);
+	
+	result = g_string_sized_new (4096);
+	
+	if (!gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL))
+		g_return_val_if_reached (NULL);
+	g_return_val_if_fail (is_priv == FALSE, NULL);
+	g_return_val_if_fail (algo != 0, NULL);
+	
+	type = gkr_ssh_proto_algo_to_keytype (algo);
+	g_return_val_if_fail (type, NULL);
+	
+	g_string_append (result, type);
+	g_string_append_c (result, ' ');
+	
+	gkr_buffer_init_full (&buffer, 4096, (GkrBufferAllocator)g_realloc);
+	gkr_ssh_proto_write_public (&buffer, algo, sexp);
+	
+	encoded = g_base64_encode (buffer.buf, buffer.len);
+	gkr_buffer_uninit (&buffer);
+	
+	g_return_val_if_fail (encoded, NULL);
+	g_string_append (result, encoded);
+	
+	if (comment) {
+		g_string_append_c (result, ' ');
+		g_string_append (result, comment);
+	}
+	
+	*n_data = result->len;
+	return (guchar*)g_string_free (result, FALSE);
+}

Added: trunk/ssh/gkr-ssh-storage.h
==============================================================================
--- (empty file)
+++ trunk/ssh/gkr-ssh-storage.h	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,46 @@
+#ifndef __GKR_SSH_STORAGE_H__
+#define __GKR_SSH_STORAGE_H__
+
+#include <glib-object.h>
+
+#include "pk/gkr-pk-storage.h"
+
+#include "pkix/gkr-pkix-types.h"
+
+G_BEGIN_DECLS
+
+#define GKR_SSH_STORAGE_ERROR            (gkr_ssh_storage_get_error_domain ())
+
+#define GKR_TYPE_SSH_STORAGE             (gkr_ssh_storage_get_type ())
+#define GKR_SSH_STORAGE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_SSH_STORAGE, GkrSshStorage))
+#define GKR_SSH_STORAGE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_SSH_STORAGE, GObject))
+#define GKR_IS_SSH_STORAGE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_SSH_STORAGE))
+#define GKR_IS_SSH_STORAGE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_SSH_STORAGE))
+#define GKR_SSH_STORAGE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_SSH_STORAGE, GkrSshStorageClass))
+
+typedef struct _GkrSshStorage GkrSshStorage;
+typedef struct _GkrSshStorageClass GkrSshStorageClass;
+
+struct _GkrSshStorage {
+	 GkrPkStorage parent;
+};
+
+struct _GkrSshStorageClass {
+	GkrPkStorageClass parent_class;
+};
+
+GType                   gkr_ssh_storage_get_type          (void) G_GNUC_CONST;
+
+GQuark 	                gkr_ssh_storage_get_error_domain  (void) G_GNUC_CONST;
+
+gboolean                gkr_ssh_storage_initialize        (void);
+
+GkrPkixResult           gkr_ssh_storage_load_public_key   (const guchar *data, gsize n_data, 
+                                                           gcry_sexp_t *sexp, gchar **comment);
+
+guchar*                 gkr_ssh_storage_write_public_key  (gcry_sexp_t sexp, gchar *comment,
+                                                           gsize *n_data);
+
+G_END_DECLS
+
+#endif /* __GKR_SSH_STORAGE_H__ */

Added: trunk/ssh/tests/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/ssh/tests/Makefile.am	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,16 @@
+
+UNIT_AUTO = \
+	unit-test-ssh-storage.c
+
+UNIT_PROMPT = 
+
+UNIT_LIBS =  \
+	$(top_builddir)/ssh/libgkr-ssh.la \
+	$(top_builddir)/pk/libgkr-pk.la \
+	$(top_builddir)/keyrings/libgkr-keyrings.la \
+	$(top_builddir)/library/libgnome-keyring-common.la \
+	$(top_builddir)/pkix/libgkr-pkix.la \
+	$(top_builddir)/common/libgkr-common.la
+
+include $(top_srcdir)/tests/test.make
+

Added: trunk/ssh/tests/unit-test-ssh-storage.c
==============================================================================
--- (empty file)
+++ trunk/ssh/tests/unit-test-ssh-storage.c	Mon Jul  7 21:17:26 2008
@@ -0,0 +1,122 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-ssh-storage.c: Test SSH storage
+
+   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 "common/gkr-location.h"
+#include "common/gkr-crypto.h"
+#include "common/gkr-secure-memory.h"
+
+#include "ssh/gkr-ssh-storage.h"
+
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* 
+ * Each test looks like (on one line):
+ *     void unit_test_xxxxx (CuTest* cu)
+ * 
+ * Each setup looks like (on one line):
+ *     void unit_setup_xxxxx (void);
+ * 
+ * Each teardown looks like (on one line):
+ *     void unit_teardown_xxxxx (void);
+ * 
+ * Tests be run in the order specified here.
+ */
+
+static const gchar *TEST_DSA_KEY = "ssh-dss AAAAB3NzaC1kc3MAAACBAJhgJycWojhw+UkvgFTdrBnCyVAZZPbbGCJ9bvoVb8N75MAmsPZugNInz6j6Iz+sa1nsYlBZnrhg4mXfxeWOTiI6/YDbPdA65P/q4oNDjKIjgBiC135un40+Qz8JGq2JPrU5pElH4jb8NYA4PymuIL7vingUvFK3XJiWSb2ZepNXAAAAFQCWBBXsX/Vi3GpSlG88Z+P8NQqmQQAAAIB0JOhEstQgJKic5Vx+C1MtBS2DX8dQ1TLo4bgzDTbYU4mbqJDUkhhYP2IGFEpuWFxLaCGsWoBfWi98Wz9o1P9TYkbmCiDd8mt7Px5bUR09orMUvHiNaLM9kH0KxUxAifGcrAsATloLJ8ReNJkypB9frjjbN1b/7YDyEP0zSiwDwwAAAIA9syAP6aY0kIdv7yqC5biGJqY170cpJYOE/vFHDVUXrXaTgPsoEQuRMFwHZbhgrVcUTKLJsmIyrpqWZ41PxDHgk1SC9GYDLmb65Pn23NvUDAZKft6E09KGL49LNpitfzLxvZAMLcU+YVCrUJwT/NgPTJ70GFrLs3z8UsKeFFxEUA== Test Comment"; 
+static const gchar *TEST_RSA_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAz8Ji7Z1/NK7tvHETqSuLWPyn4l0fF6lTTbYf9Jx21RtaNwmaCi9u1Id3wVQMtuuR+0NLoBPyVdDrWi6ap9TkKdNQnnqW4Ang+GZc+9sXzbgWmgXnjKTXo+EcpMJLqpTLXPcaxYtwGIL/K/BE7NJ9i43HPqUG5z8ezE1/iHkfHMk= stef memberwebs com"; 
+static const gchar *TEST_COMMENT_KEY = "# a line that shouldn't be parsed \n\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAz8Ji7Z1/NK7tvHETqSuLWPyn4l0fF6lTTbYf9Jx21RtaNwmaCi9u1Id3wVQMtuuR+0NLoBPyVdDrWi6ap9TkKdNQnnqW4Ang+GZc+9sXzbgWmgXnjKTXo+EcpMJLqpTLXPcaxYtwGIL/K/BE7NJ9i43HPqUG5z8ezE1/iHkfHMk= stef memberwebs com\n# \n"; 
+
+void unit_test_ssh_public_dsa (CuTest* cu)
+{
+	GkrPkixResult res;
+	gcry_sexp_t sexp;
+	gchar *comment;
+	int algo;
+	guchar *data;
+	gsize n_data;
+	gboolean ret, is_priv;
+	
+	res = gkr_ssh_storage_load_public_key ((guchar*)TEST_DSA_KEY, strlen (TEST_DSA_KEY), &sexp, &comment); 
+	CuAssert (cu, "couldn't parse public SSH DSA key", res == GKR_PKIX_SUCCESS);
+	CuAssert (cu, "Bad comment on public SSH DSA key", comment && strcmp (comment, "Test Comment") == 0);
+	
+	ret = gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL);
+	CuAssert (cu, "bad SSH DSA key parsed", ret == TRUE);
+	CuAssert (cu, "wrong algorithm in SSH DSA key parsed", algo == GCRY_PK_DSA);
+	CuAssert (cu, "bad key type in SSH DSA key parsed", is_priv == FALSE);
+	
+	gkr_crypto_sexp_dump (sexp);
+	
+	data = gkr_ssh_storage_write_public_key (sexp, comment, &n_data);
+	CuAssert (cu, "Couldn't write SSH DSA key", data != NULL);
+	CuAssert (cu, "Written SSH key invalid length", n_data == strlen (TEST_DSA_KEY));
+	CuAssert (cu, "Wrote invalid SSH DSA key", strncmp (TEST_DSA_KEY, (gchar*)data, n_data) == 0);
+}
+
+void unit_test_ssh_public_rsa (CuTest *cu)
+{
+	GkrPkixResult res;
+	gcry_sexp_t sexp;
+	gchar *comment;
+	int algo;
+	guchar *data, *data2;
+	gsize n_data, n_data2;
+	gboolean ret, is_priv;
+	
+	/* RSA */
+	
+	res = gkr_ssh_storage_load_public_key ((guchar*)TEST_RSA_KEY, strlen (TEST_RSA_KEY), &sexp, &comment); 
+	CuAssert (cu, "couldn't parse public SSH RSA key", res == GKR_PKIX_SUCCESS);
+	CuAssert (cu, "Bad comment on public SSH RSA key", comment && strcmp (comment, "stef memberwebs com") == 0);
+	
+	ret = gkr_crypto_skey_parse (sexp, &algo, &is_priv, NULL);
+	CuAssert (cu, "bad SSH RSA key parsed", ret == TRUE);
+	CuAssert (cu, "wrong algorithm in SSH RSA key parsed", algo == GCRY_PK_RSA);
+	CuAssert (cu, "bad key type in SSH RSA key parsed", is_priv == FALSE);
+
+	gkr_crypto_sexp_dump (sexp);
+
+	data = gkr_ssh_storage_write_public_key (sexp, comment, &n_data);
+	CuAssert (cu, "Couldn't write SSH RSA key", data != NULL);
+	CuAssert (cu, "Written SSH key invalid length", n_data == strlen (TEST_RSA_KEY));
+	CuAssert (cu, "Wrote invalid SSH RSA key", memcmp (TEST_RSA_KEY, data, n_data) == 0);
+
+	/* The same RSA key with comments */
+	
+	res = gkr_ssh_storage_load_public_key ((guchar*)TEST_COMMENT_KEY, strlen (TEST_COMMENT_KEY), &sexp, &comment); 
+	CuAssert (cu, "couldn't parse public SSH RSA key", res == GKR_PKIX_SUCCESS);
+	
+	gkr_crypto_sexp_dump (sexp);
+
+	data2 = gkr_ssh_storage_write_public_key (sexp, comment, &n_data2);
+	CuAssert (cu, "Couldn't write SSH RSA key", data != NULL);
+	CuAssert (cu, "Written SSH key invalid length", n_data == n_data2);
+	CuAssert (cu, "Wrote invalid SSH RSA key", memcmp (data, data2, n_data) == 0);	
+}



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