gnome-keyring r1441 - in trunk: . gp11 pkcs11/ssh-agent



Author: nnielsen
Date: Tue Jan  6 03:13:26 2009
New Revision: 1441
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1441&view=rev

Log:
	* gp11/gp11.h:
	* gp11/gp11-slot.c: Helper function for matching mechanism types.
	
	* pkcs11/ssh-agent/gck-ssh-agent.c:
	* pkcs11/ssh-agent/gck-ssh-agent.h:
	* pkcs11/ssh-agent/gck-ssh-agent-ops.c:
	* pkcs11/ssh-agent/gck-ssh-agent-private.h:
	* pkcs11/ssh-agent/gck-ssh-agent-standalone.c: The modular ssh agent now 
	uses keys from any available PKCS#11 slots, and automatically selects a decent
	slot for it's session keys.


Modified:
   trunk/ChangeLog
   trunk/gp11/gp11-slot.c
   trunk/gp11/gp11.h
   trunk/pkcs11/ssh-agent/gck-ssh-agent-ops.c
   trunk/pkcs11/ssh-agent/gck-ssh-agent-private.h
   trunk/pkcs11/ssh-agent/gck-ssh-agent-standalone.c
   trunk/pkcs11/ssh-agent/gck-ssh-agent.c
   trunk/pkcs11/ssh-agent/gck-ssh-agent.h

Modified: trunk/gp11/gp11-slot.c
==============================================================================
--- trunk/gp11/gp11-slot.c	(original)
+++ trunk/gp11/gp11-slot.c	Tue Jan  6 03:13:26 2009
@@ -270,6 +270,50 @@
 }
 
 /**
+ * gp11_mechanisms_check:
+ * @mechanisms: A list of mechanisms, perhaps retrieved from gp11_slot_get_mechanisms().
+ * 
+ * Check whether all the mechanism types are in the list.
+ * 
+ * The arguments should be a list of CKM_XXX mechanism types. The last argument
+ * should be GP11_INVALID. 
+ * 
+ * Return value: Whether the mechanism is in the list or not.
+ **/
+gboolean
+gp11_mechanisms_check (GP11Mechanisms *mechanisms, ...)
+{
+	gboolean found = TRUE;
+	va_list va;
+	gulong mech;
+	gsize i;
+	
+	g_return_val_if_fail (mechanisms, FALSE);
+	
+	va_start (va, mechanisms);
+	for (;;) {
+		mech = va_arg (va, gulong);
+		if (mech == GP11_INVALID)
+			break;
+		
+		found = FALSE;
+		for (i = 0; i < gp11_mechanisms_length (mechanisms); ++i) {
+			if (gp11_mechanisms_at (mechanisms, i) == mech) {
+				found = TRUE;
+				break;
+			}
+		}
+		
+		if (found == FALSE)
+			break;
+		
+	}
+	va_end (va);
+	
+	return found;
+}
+
+/**
  * gp11_slot_get_handle:
  * @self: The slot to get the handle of.
  * 

Modified: trunk/gp11/gp11.h
==============================================================================
--- trunk/gp11/gp11.h	(original)
+++ trunk/gp11/gp11.h	Tue Jan  6 03:13:26 2009
@@ -387,6 +387,9 @@
 
 #define gp11_mechanisms_free(a)         (g_array_free(a, TRUE))
 
+gboolean            gp11_mechanisms_check                   (GP11Mechanisms *mechanisms,
+                                                             ...);
+
 #define GP11_TYPE_SLOT             (gp11_slot_get_type())
 #define GP11_SLOT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), GP11_TYPE_SLOT, GP11Slot))
 #define GP11_SLOT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), GP11_TYPE_SLOT, GP11Slot))

Modified: trunk/pkcs11/ssh-agent/gck-ssh-agent-ops.c
==============================================================================
--- trunk/pkcs11/ssh-agent/gck-ssh-agent-ops.c	(original)
+++ trunk/pkcs11/ssh-agent/gck-ssh-agent-ops.c	Tue Jan  6 03:13:26 2009
@@ -40,6 +40,7 @@
 
 /* ---------------------------------------------------------------------------- */
 
+
 static void
 copy_attribute (GP11Attributes *original, CK_ATTRIBUTE_TYPE type, GP11Attributes *dest)
 {
@@ -53,16 +54,12 @@
 		gp11_attributes_add (dest, attr);
 }
 
-static GList*
-find_keys_for_attributes (GP11Session *session, GP11Attributes *attrs, 
-                          CK_OBJECT_CLASS klass)
+static GP11Attributes*
+build_like_attributes (GP11Attributes *attrs, CK_OBJECT_CLASS klass)
 {
 	GP11Attributes *search;
-	GError *error = NULL;
 	gulong key_type;
-	GList *keys;
 	
-	g_assert (GP11_IS_SESSION (session));
 	g_assert (attrs);
 	
 	/* Determine the key type */
@@ -92,97 +89,257 @@
 		break;
 	}
 	
-	keys = gp11_session_find_objects_full (session, search, NULL, &error);
-	gp11_attributes_unref (search);
+	return search;
+}
+
+static void
+search_keys_like_attributes (gpointer session_or_module, GP11Attributes *attrs, CK_OBJECT_CLASS klass, 
+                             GP11ObjectForeachFunc func, gpointer user_data)
+{
+	GP11Attributes *search;
+	GError *error = NULL;
+	GList *keys, *l;
 	
-	if (error) {
-		g_warning ("couldn't search for matching keys: %s", error->message);
-		g_clear_error (&error);
-		return NULL;
+	search = build_like_attributes (attrs, klass);
+	
+	/* In all slots */
+	if (GP11_IS_MODULE (session_or_module)) {
+		if (!gp11_module_enumerate_objects_full (session_or_module, search, NULL, 
+		                                         func, user_data, &error)) {
+			g_warning ("couldn't enumerate matching keys: %s", error->message);
+			g_clear_error (&error);
+		}
+		
+	/* Otherwise search in the session */
+	} else if (GP11_IS_SESSION (session_or_module)){
+		keys = gp11_session_find_objects_full (session_or_module, search, NULL, &error);
+		
+		if (error) {
+			g_warning ("couldn't find matching keys: %s", error->message);
+			g_clear_error (&error);
+			
+		} else {
+			for (l = keys; l; l = g_list_next (l)) {
+				if (!(func) (l->data, user_data))
+					break;
+			}
+			
+			gp11_list_unref_free (keys);
+		}
+		
+	/* Bad object passed in */
+	} else {
+		g_assert_not_reached ();
 	}
 	
-	return keys;
+	gp11_attributes_unref (search);
 }
 
-static GP11Object*
-public_key_for_attributes (GP11Session *session, GP11Attributes *attrs)
+static gboolean
+list_all_matching (GP11Object *object, gpointer user_data)
 {
-	GList *keys;
-	GP11Object *object;
+	GList** list = (GList**)user_data;
+	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	*list = g_list_prepend (*list, g_object_ref (object));
 	
-	g_assert (GP11_IS_SESSION (session));
-	g_assert (attrs);
+	/* Keep going */
+	return TRUE;
+}
+
+static gboolean
+return_first_matching (GP11Object *object, gpointer user_data)
+{
+	GP11Object **result = (GP11Object**)user_data;
 	
-	keys = find_keys_for_attributes (session, attrs, CKO_PUBLIC_KEY);
-	if (!keys) {
-		g_message ("couldn't find matching public key");
-		return NULL;
-	}
+	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (*result == NULL, FALSE);
+	*result = g_object_ref (object);
 	
-	object = g_object_ref (keys->data);
-	gp11_list_unref_free (keys);
-	return object;
+	/* We've seen enough */
+	return FALSE;
 }
 
-static GP11Object*
-private_key_for_public (GP11Session *session, GP11Object *pub)
+static gboolean
+return_private_matching (GP11Object *object, gpointer user_data)
 {
-	GP11Object *priv = NULL;
+	GP11Object **result = (GP11Object**)user_data;
+	GP11Session *session;
 	GP11Attributes *attrs;
-	GError *error = NULL;
+	GP11Attribute *attr;
+	gboolean token;
 	GList *objects;
-
-	g_assert (GP11_IS_SESSION (session));
-	g_assert (GP11_IS_OBJECT (pub));
-
-	gp11_object_set_session (pub, session);
-	attrs = gp11_object_get (pub, &error, CKA_ID, CKA_TOKEN, 
-	                         GP11_INVALID);
+	GError *error = NULL;
+	
+	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (*result == NULL, FALSE);
+	
+	/* Get the key identifier and token */
+	attrs = gp11_object_get (object, &error, CKA_ID, CKA_TOKEN, -1);
 	if (error) {
-		g_warning ("couldn't lookup attributes for key: %s", error->message);
+		g_warning ("error retrieving attributes for public key: %s", error->message);
 		g_clear_error (&error);
-		return NULL;
+		return TRUE;
 	}
+
+	/* Dig out the key identifier and token */
+	attr = gp11_attributes_find (attrs, CKA_ID);
+	g_return_val_if_fail (attr, FALSE);
 	
-	/* Search for exactly the same attributes but with a private key class */
-	gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_PRIVATE_KEY);
-	objects = gp11_session_find_objects_full (session, attrs, NULL, &error);
+	if (!gp11_attributes_find_boolean (attrs, CKA_TOKEN, &token))
+		token = FALSE;
+	
+	session = gp11_object_get_session (object);
+	g_return_val_if_fail (GP11_IS_SESSION (session), FALSE);
+		
+	/* Search for the matching private key */
+	objects = gp11_session_find_objects (session, NULL, 
+	                                     CKA_ID, attr->length, attr->value,
+	                                     CKA_CLASS, GP11_ULONG, CKO_PRIVATE_KEY,
+	                                     CKA_TOKEN, GP11_BOOLEAN, token,
+	                                     GP11_INVALID);
+		
 	gp11_attributes_unref (attrs);
+		
+	/* Keep searching, not found */
+	if (objects) {
+		*result = g_object_ref (objects->data);
+		gp11_object_set_session (*result, session);
+		gp11_list_unref_free (objects);
+	}
+
+	g_object_unref (session);
+
+	/* Stop once we have a key */
+	return (*result == NULL);
+}
+
+static gboolean 
+load_identity_v1_attributes (GP11Object *object, gpointer user_data)
+{
+	GP11Attributes *attrs;
+	GP11Attribute *attr;
+	GP11Session *session;
+	GError *error = NULL;
+	gboolean valid = TRUE;
+	GList **all_attrs;
+	GList *objects;
+	
+	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (user_data, FALSE);
 	
+	/* 
+	 * The encompassing search should have limited to the right label.
+	 * In addition V1 keys are only RSA.
+	 */
+	
+	attrs = gp11_object_get (object, &error, CKA_ID, CKA_LABEL, CKA_KEY_TYPE, CKA_MODULUS, 
+	                         CKA_PUBLIC_EXPONENT, CKA_CLASS, CKA_MODULUS_BITS, -1);
 	if (error) {
-		g_warning ("couldn't search for related key: %s", error->message);
+		g_warning ("error retrieving attributes for public key: %s", error->message);
 		g_clear_error (&error);
-		return NULL;
+		return TRUE;
 	}
+
+	/* Find a private key for this one */
+	attr = gp11_attributes_find (attrs, CKA_ID);
+	if (attr != NULL) {
+		session = gp11_object_get_session (object);
+		g_return_val_if_fail (GP11_IS_SESSION (session), FALSE);
+		
+		objects = gp11_session_find_objects (session, NULL, 
+		                                     CKA_ID, attr->length, attr->value,
+		                                     CKA_CLASS, GP11_ULONG, CKO_PRIVATE_KEY,
+		                                     CKA_TOKEN, GP11_BOOLEAN, FALSE,
+		                                     GP11_INVALID);
+		
+		g_object_unref (session);
+		
+		if (!objects)
+			valid = FALSE;
+
+		gp11_list_unref_free (objects);
+	}
+	
+	all_attrs = (GList**)user_data;
+	if (valid == TRUE)
+		*all_attrs = g_list_prepend (*all_attrs, attrs);
+	else 
+		gp11_attributes_unref (attrs);
 	
-	if (objects)
-		priv = g_object_ref (objects->data);
-	gp11_list_unref_free (objects);
-	
-	return priv;
+	/* Note that we haven't reffed the object or session */
+
+	/* Keep going */
+	return TRUE;
 }
 
-static GP11Object*
-private_key_for_attributes (GP11Session *session, GP11Attributes *attrs)
+static gboolean 
+load_identity_v2_attributes (GP11Object *object, gpointer user_data)
 {
-	GP11Object *pub, *prv;
-	
-	g_assert (GP11_IS_SESSION (session));
-	g_assert (attrs);
+	GP11Attributes *attrs;
+	GP11Attribute *attr;
+	GP11Session *session;
+	GError *error = NULL;
+	gboolean valid = TRUE;
+	gboolean token;
+	GList **all_attrs;
+	GList *objects;
 	
-	pub = public_key_for_attributes (session, attrs);
-	if (pub == NULL)
-		return NULL;
+	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (user_data, FALSE);
 	
-	prv = private_key_for_public (session, pub);
-	g_object_unref (pub);
+	attrs = gp11_object_get (object, &error, CKA_ID, CKA_LABEL, CKA_KEY_TYPE, CKA_MODULUS, 
+	                         CKA_PUBLIC_EXPONENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, 
+	                         CKA_VALUE, CKA_CLASS, CKA_MODULUS_BITS, CKA_TOKEN, -1);
+	if (error) {
+		g_warning ("error retrieving attributes for public key: %s", error->message);
+		g_clear_error (&error);
+		return TRUE;
+	}
 	
-	if (prv == NULL) {
-		g_message ("couldn't find matching private key");
-		return NULL;
+	/* Dig out the label, and see if it's not v1, skip if so */
+	attr = gp11_attributes_find (attrs, CKA_LABEL);
+	if (attr != NULL) {
+		if (attr->length == strlen (V1_LABEL) && 
+		    strncmp ((gchar*)attr->value, V1_LABEL, attr->length) == 0)
+			valid = FALSE;
 	}
 	
-	return prv;
+	/* Figure out if it's a token object or not */
+	if (!gp11_attributes_find_boolean (attrs, CKA_TOKEN, &token))
+		token = FALSE;
+
+	/* Find a private key for this one */
+	attr = gp11_attributes_find (attrs, CKA_ID);
+	if (attr != NULL) {
+		session = gp11_object_get_session (object);
+		g_return_val_if_fail (GP11_IS_SESSION (session), FALSE);
+		
+		objects = gp11_session_find_objects (session, NULL, 
+		                                     CKA_ID, attr->length, attr->value,
+		                                     CKA_CLASS, GP11_ULONG, CKO_PRIVATE_KEY,
+		                                     CKA_TOKEN, GP11_BOOLEAN, token,
+		                                     GP11_INVALID);
+		
+		g_object_unref (session);
+		
+		if (!objects)
+			valid = FALSE;
+
+		gp11_list_unref_free (objects);
+	}
+	
+	all_attrs = (GList**)user_data;
+	if (valid == TRUE)
+		*all_attrs = g_list_prepend (*all_attrs, attrs);
+	else 
+		gp11_attributes_unref (attrs);
+	
+	/* Note that we haven't reffed the object or session */
+	
+	/* Keep going */
+	return TRUE;
 }
 
 static void
@@ -222,21 +379,7 @@
 }
 
 static void
-remove_by_public_key (GP11Session *session, GP11Object *pub)
-{
-	GP11Object *priv;
-	
-	g_assert (GP11_IS_SESSION (session));
-	g_assert (GP11_IS_OBJECT (pub));
-	
-	priv = private_key_for_public (session, pub);
-	remove_key_pair (session, priv, pub);
-	if (pub != NULL)
-		g_object_unref (priv);
-}
-
-static void
-remove_or_lock_by_public_key (GP11Session *session, GP11Object *pub)
+remove_by_public_key (GP11Session *session, GP11Object *pub, gboolean exclude_v1)
 {
 	GP11Attributes *attrs;
 	GError *error = NULL;
@@ -258,7 +401,7 @@
 	}
 	
 	/* Skip over SSH V1 keys */
-	if (gp11_attributes_find_string (attrs, CKA_LABEL, &label)) {
+	if (exclude_v1 && gp11_attributes_find_string (attrs, CKA_LABEL, &label)) {
 		if (label && strcmp (label, V1_LABEL) == 0) {
 			gp11_attributes_unref (attrs);
 			g_free (label);
@@ -358,8 +501,9 @@
 	gp11_attributes_add_boolean (pub, CKA_TOKEN, FALSE);
 	
 	/* Find the previous keys that match the same description */
-	priv_prev = find_keys_for_attributes (session, priv, CKO_PRIVATE_KEY);
-	pub_prev = find_keys_for_attributes (session, pub, CKO_PUBLIC_KEY);
+	priv_prev = pub_prev = NULL;
+	search_keys_like_attributes (session, priv, CKO_PRIVATE_KEY, list_all_matching, &priv_prev);
+	search_keys_like_attributes (session, priv, CKO_PUBLIC_KEY, list_all_matching, &pub_prev);
 	
 	/* Now try and create the new keys */
 	if (create_key_pair (session, priv, pub)) {
@@ -504,68 +648,22 @@
 static gboolean
 op_request_identities (GckSshAgentCall *call)
 {
-	GList *objects, *l;
-	GList *all_attrs;
-	GError *error = NULL;
+	GList *all_attrs, *l;
 	GP11Attributes *attrs;
-	GP11Object *pub, *priv;
-	GP11Attribute *label;
 	gsize blobpos;
 	gchar *comment;
 
-	/* Find all the private keys*/
+	/* Find all the keys (we filter out v1 later) */
 	/* TODO: Check SSH purpose */
-	objects = gp11_session_find_objects (call->session, &error,
-	                                     CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
-	                                     GP11_INVALID);
-	if (error) {
-		g_warning ("couldn't search for private keys: %s", error->message);
-		g_clear_error (&error);
+	all_attrs = NULL;
+	if (!gp11_module_enumerate_objects (call->module, 
+	                                    load_identity_v2_attributes, &all_attrs,
+	                                    CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
+	                                    GP11_INVALID)) {
 		gkr_buffer_add_byte (call->resp, GCK_SSH_RES_FAILURE);
 		return TRUE;
 	}
 	
-	/* Find the public key, and load attributes for each public */
-	for (l = objects; l; l = g_list_next (l)) {
-		pub = l->data;
-		
-		/* For each public key we find a private key. */
-		priv = private_key_for_public (call->session, pub);
-		if (priv == NULL) 
-			continue;
-		g_object_unref (priv);
-		
-		/*
-		 * Now get attributes for that public key. Any attributes not present on 
-		 * the key will be returned as invalid.
-		 */
-		gp11_object_set_session (pub, call->session);
-		attrs = gp11_object_get (pub, &error, CKA_LABEL, CKA_KEY_TYPE, CKA_MODULUS, 
-		                         CKA_PUBLIC_EXPONENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, 
-		                         CKA_VALUE, CKA_CLASS, CKA_MODULUS_BITS, -1);
-		
-		if (error) {
-			g_warning ("error retrieving attributes for public key: %s", error->message);
-			g_clear_error (&error);
-			continue;
-		}
-		
-		/* Dig out the label, and see if it's not v1, skip if so */
-		label = gp11_attributes_find (attrs, CKA_LABEL);
-		if (label != NULL) {
-			if (label->length == strlen (V1_LABEL) && 
-			    strncmp ((gchar*)label->value, V1_LABEL, label->length) == 0) {
-				gp11_attributes_unref (attrs);
-				continue;
-			}
-		}
-
-		/* We have this one squared away and ready to send */
-		all_attrs = g_list_prepend (all_attrs, attrs);
-	}
-	
-	gp11_list_unref_free (objects);
-	
 	gkr_buffer_add_byte (call->resp, GCK_SSH_RES_IDENTITIES_ANSWER);
 	gkr_buffer_add_uint32 (call->resp, g_list_length (all_attrs));
 	      
@@ -602,56 +700,22 @@
 static gboolean
 op_v1_request_identities (GckSshAgentCall *call)
 {
-	GList *objects, *l;
-	GError *error = NULL;
-	GList *all_attrs;
+	GList *all_attrs, *l;
 	GP11Attributes *attrs;
-	GP11Object *pub, *priv;
-
+	
 	/* Find all the keys not on token, and are V1 */
 	/* TODO: Check SSH purpose */
-	objects = gp11_session_find_objects (call->session, &error, 
-	                                     CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
-	                                     CKA_TOKEN, GP11_BOOLEAN, FALSE,
-	                                     CKA_LABEL, GP11_STRING, V1_LABEL,
-	                                     GP11_INVALID);
-	if (error) {
-		g_warning ("couldn't search for public keys: %s", error->message);
-		g_clear_error (&error);
+	all_attrs = NULL;
+	if (!gp11_module_enumerate_objects (call->module, 
+	                                    load_identity_v1_attributes, &all_attrs,
+	                                    CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
+	                                    CKA_TOKEN, GP11_BOOLEAN, FALSE,
+	                                    CKA_LABEL, GP11_STRING, V1_LABEL,
+	                                    GP11_INVALID)) {
 		gkr_buffer_add_byte (call->resp, GCK_SSH_RES_FAILURE);
 		return TRUE;
 	}
 	
-	/* Find the public key, and load attributes for each public */
-	for (l = objects; l; l = g_list_next (l)) {
-		pub = l->data;
-		
-		/* For each public key we find a private key. */
-		priv = private_key_for_public (call->session, pub);
-		if (priv == NULL) 
-			continue;
-		g_object_unref (priv);
-		
-		/*
-		 * Now get attributes for that public key. Any attributes not present on 
-		 * the key will be returned as invalid.
-		 */
-		gp11_object_set_session (pub, call->session);
-		attrs = gp11_object_get (pub, &error, CKA_KEY_TYPE, CKA_MODULUS, 
-		                         CKA_PUBLIC_EXPONENT, CKA_MODULUS_BITS, CKA_CLASS, -1);
-		
-		if (error) {
-			g_warning ("error retrieving attributes for public key: %s", error->message);
-			g_clear_error (&error);
-			continue;
-		}
-
-		/* We have this one squared away and ready to send */
-		all_attrs = g_list_prepend (all_attrs, attrs);
-	}
-	
-	gp11_list_unref_free (objects);
-	
 	gkr_buffer_add_byte (call->resp, GCK_SSH_RES_RSA_IDENTITIES_ANSWER);
 	gkr_buffer_add_uint32 (call->resp, g_list_length (all_attrs));
 	      
@@ -747,9 +811,10 @@
 {
 	GP11Attributes *attrs;
 	GError *error = NULL;
+	GP11Object *key = NULL;
 	const guchar *data;
 	const gchar *salgo;
-	GP11Object *key;
+	GP11Session *session;
 	guchar *result;
 	gsize n_data, n_result;
 	guint32 flags;
@@ -787,7 +852,7 @@
 	}
 
 	/* Lookup the key */
-	key = private_key_for_attributes (call->session, attrs);
+	search_keys_like_attributes (call->module, attrs, CKO_PUBLIC_KEY, return_private_matching, &key);
 	gp11_attributes_unref (attrs);
 	
 	if (!key) {
@@ -807,8 +872,13 @@
 	else
 		hash = make_raw_sign_hash (halgo, data, n_data, &n_hash);
 	
+	session = gp11_object_get_session (key);
+	g_return_val_if_fail (session, FALSE);
+	
 	/* Do the magic */
-	result = gp11_session_sign (call->session, key, mech, hash, n_hash, &n_result, &error);
+	result = gp11_session_sign (session, key, mech, hash, n_hash, &n_result, &error);
+	
+	g_object_unref (session);
 	g_object_unref (key);
 	g_free (hash);
 	
@@ -855,6 +925,7 @@
 op_v1_challenge (GckSshAgentCall *call)
 {
 	gsize offset, n_data, n_result, n_hash;
+	GP11Session *session;
 	GP11Attributes *attrs;
 	guchar session_id[16];
 	guint8 hash[16];
@@ -910,7 +981,7 @@
 	}
 	
 	/* Lookup the key */
-	key = private_key_for_attributes (call->session, attrs);
+	search_keys_like_attributes (call->module, attrs, CKO_PUBLIC_KEY, return_private_matching, &key);
 	gp11_attributes_unref (attrs);
 	
 	/* Didn't find a key? */
@@ -919,7 +990,12 @@
 		return TRUE;
 	}
 
-	result = gp11_session_decrypt (call->session, key, CKM_RSA_PKCS, data, n_data, &n_result, &error);
+	session = gp11_object_get_session (key);
+	g_return_val_if_fail (session, FALSE);
+	
+	result = gp11_session_decrypt (session, key, CKM_RSA_PKCS, data, n_data, &n_result, &error);
+	
+	g_object_unref (session);
 	g_object_unref (key);
 	
 	if (error) {
@@ -948,7 +1024,7 @@
 {
 	GP11Attributes *attrs;
 	GP11Session *session;
-	GP11Object *key;
+	GP11Object *key = NULL;
 	gsize offset;
 	guint sz;
 	
@@ -964,27 +1040,27 @@
 		gp11_attributes_unref (attrs);
 		return FALSE;
 	}
+
+	/* 
+	 * This is the session that owns these objects. Only 
+	 * one thread can use it at a time. 
+	 */
 	
-	key = public_key_for_attributes (call->session, attrs);
+	session = gck_ssh_agent_checkout_main_session ();
+	g_return_val_if_fail (session, FALSE);
+
+	search_keys_like_attributes (session, attrs, CKO_PUBLIC_KEY, return_first_matching, &key);
 	gp11_attributes_unref (attrs);
 	
 	if (key != NULL) { 
-		
-		/* 
-		 * This is the session that owns these objects. Only 
-		 * one thread can use it at a time. 
-		 */
-		
-		session = gck_ssh_agent_checkout_main_session ();
-		g_return_val_if_fail (session, FALSE);
-		
-		remove_or_lock_by_public_key (session, key);
-		
-		gck_ssh_agent_checkin_main_session (session);
-
+		remove_by_public_key (session, key, TRUE);
 		g_object_unref (key);
 	}
 
+	gck_ssh_agent_checkin_main_session (session);
+
+	/* TODO: Implement locking of other keys */
+
 	gkr_buffer_add_byte (call->resp, GCK_SSH_RES_SUCCESS);
 
 	return TRUE;	
@@ -995,7 +1071,7 @@
 {
 	GP11Session *session;
 	GP11Attributes *attrs;
-	GP11Object *key;
+	GP11Object *key = NULL;
 	gsize offset;
 	
 	offset = 5;
@@ -1005,32 +1081,25 @@
 		gp11_attributes_unref (attrs);		
 		return FALSE;
 	}
-	
-	key = public_key_for_attributes (call->session, attrs);
-	gp11_attributes_unref (attrs);
-	
+
 	/* 
 	 * This is the session that owns these objects. Only 
 	 * one thread can use it at a time. 
 	 */
+
+	session = gck_ssh_agent_checkout_main_session ();
+	g_return_val_if_fail (session, FALSE);
+
+	search_keys_like_attributes (session, attrs, CKO_PUBLIC_KEY, return_first_matching, &key);
+	gp11_attributes_unref (attrs);
 	
 	if (key != NULL) { 
-		
-		/* 
-		 * This is the session that owns these objects. Only 
-		 * one thread can use it at a time. 
-		 */
-		
-		session = gck_ssh_agent_checkout_main_session ();
-		g_return_val_if_fail (session, FALSE);
-		
-		remove_by_public_key (session, key);
-		
-		gck_ssh_agent_checkin_main_session (session);
-		
+		remove_by_public_key (session, key, FALSE);
 		g_object_unref (key);
 	}
-	
+
+	gck_ssh_agent_checkin_main_session (session);
+
 	gkr_buffer_add_byte (call->resp, GCK_SSH_RES_SUCCESS);
 	return TRUE;	
 }
@@ -1042,12 +1111,6 @@
 	GList *objects, *l;
 	GError *error = NULL;
 	
-	/* Find all session SSH public keys */
-	objects = gp11_session_find_objects (call->session, &error,
-	                                     CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
-	                                     GP11_INVALID);
-
-
 	/* 
 	 * This is the session that owns these objects. Only 
 	 * one thread can use it at a time. 
@@ -1055,14 +1118,22 @@
 	
 	session = gck_ssh_agent_checkout_main_session ();
 	g_return_val_if_fail (session, FALSE);
+	
+	/* Find all session SSH public keys */
+	objects = gp11_session_find_objects (session, &error,
+	                                     CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
+	                                     GP11_INVALID);
+	
 
 	for (l = objects; l; l = g_list_next (l)) 
-		remove_or_lock_by_public_key (session, l->data);
+		remove_by_public_key (session, l->data, TRUE);
 
-	gck_ssh_agent_checkin_main_session (session);
-	
 	gp11_list_unref_free (objects);
+
+	gck_ssh_agent_checkin_main_session (session);
 	
+	/* TODO: Go through all open tokens and lock private SSH keys */
+
 	gkr_buffer_add_byte (call->resp, GCK_SSH_RES_SUCCESS);
 	return TRUE;
 }
@@ -1073,13 +1144,6 @@
 	GP11Session *session;
 	GList *objects, *l;
 	GError *error = NULL;
-	
-	/* Find all session SSH v1 public keys */
-	objects = gp11_session_find_objects (call->session, &error,
-	                                     CKA_TOKEN, GP11_BOOLEAN, FALSE,
-	                                     CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
-	                                     CKA_LABEL, GP11_STRING, V1_LABEL,
-	                                     GP11_INVALID);
 
 	/* 
 	 * This is the session that owns these objects. Only 
@@ -1089,13 +1153,20 @@
 	session = gck_ssh_agent_checkout_main_session ();
 	g_return_val_if_fail (session, FALSE);
 
+	/* Find all session SSH v1 public keys */
+	objects = gp11_session_find_objects (session, &error,
+	                                     CKA_TOKEN, GP11_BOOLEAN, FALSE,
+	                                     CKA_CLASS, GP11_ULONG, CKO_PUBLIC_KEY,
+	                                     CKA_LABEL, GP11_STRING, V1_LABEL,
+	                                     GP11_INVALID);
+
 	for (l = objects; l; l = g_list_next (l)) 
-		remove_by_public_key (session, l->data);
+		remove_by_public_key (session, l->data, FALSE);
+
+	gp11_list_unref_free (objects);
 
 	gck_ssh_agent_checkin_main_session (session);
 		
-	gp11_list_unref_free (objects);
-	
 	gkr_buffer_add_byte (call->resp, GCK_SSH_RES_SUCCESS);
 	return TRUE;
 }

Modified: trunk/pkcs11/ssh-agent/gck-ssh-agent-private.h
==============================================================================
--- trunk/pkcs11/ssh-agent/gck-ssh-agent-private.h	(original)
+++ trunk/pkcs11/ssh-agent/gck-ssh-agent-private.h	Tue Jan  6 03:13:26 2009
@@ -33,7 +33,7 @@
 
 typedef struct _GckSshAgentCall {
 	int sock;
-	GP11Session *session;
+	GP11Module *module;
 	GkrBuffer *req;
 	GkrBuffer *resp;
 } GckSshAgentCall;
@@ -91,6 +91,8 @@
  * gck-ssh-agent.c
  */
 
+int                   gck_ssh_agent_initialize_with_module          (const gchar *prefix, GP11Module *module);
+
 GP11Session*          gck_ssh_agent_checkout_main_session           (void);
 
 void                  gck_ssh_agent_checkin_main_session            (GP11Session* session);

Modified: trunk/pkcs11/ssh-agent/gck-ssh-agent-standalone.c
==============================================================================
--- trunk/pkcs11/ssh-agent/gck-ssh-agent-standalone.c	(original)
+++ trunk/pkcs11/ssh-agent/gck-ssh-agent-standalone.c	Tue Jan  6 03:13:26 2009
@@ -22,12 +22,20 @@
 
 #include "config.h"
 
-#include <glib.h>
-
 #include "gck-ssh-agent.h"
+#include "gck-ssh-agent-private.h"
 
 #include "common/gkr-secure-memory.h"
 
+#include "gp11/gp11.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pwd.h>
+#include <string.h>
+#include <unistd.h>
+
 G_LOCK_DEFINE_STATIC (memory_mutex);
 
 void gkr_memory_lock (void)
@@ -72,11 +80,10 @@
 main(int argc, char *argv[])
 {
 	GP11Module *module;
-	GList *slots;
-	GP11Slot *slot;
 	GError *error = NULL;
 	GIOChannel *channel;
 	GMainLoop *loop;
+	int sock;
 	
 	g_type_init ();
 	
@@ -90,28 +97,22 @@
 		return 1;
 	}
 	
-	/* This is currently brittle because it's just used for development */
-	slots = gp11_module_get_slots (module, TRUE);
-	if (!slots) {
-		g_message ("no slots present in pkcs11 module");
-		return 1;
-	}
-
-	slot = g_object_ref (slots->data);
-	gp11_list_unref_free (slots);
 	
 	g_signal_connect (module, "authenticate-slot", G_CALLBACK (authenticate_slot), NULL);
 	g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL);
 	gp11_module_set_auto_authenticate (module, TRUE);
 
-	if (!gck_ssh_agent_initialize ("/tmp/test-gck-ssh-agent", slot))
+	sock = gck_ssh_agent_initialize_with_module ("/tmp/test-gck-ssh-agent", module);
+	g_object_unref (module);
+	
+	if (sock == -1)
 		return 1;
 	
-	channel = g_io_channel_unix_new (gck_ssh_agent_get_socket_fd ());
+	channel = g_io_channel_unix_new (sock);
 	g_io_add_watch (channel, G_IO_IN | G_IO_HUP, accept_client, NULL);
 	g_io_channel_unref (channel);
 
-	g_print ("SSH_AUTH_SOCK=%s\n", gck_ssh_agent_get_socket_path ());
+	g_print ("SSH_AUTH_SOCK=%s\n", g_getenv ("SSH_AUTH_SOCK"));
 	
 	/* Run a main loop */
 	loop = g_main_loop_new (NULL, FALSE);
@@ -119,7 +120,6 @@
 	g_main_loop_unref (loop);
 	
 	gck_ssh_agent_uninitialize ();
-	g_object_unref (slot);
 	
 	return 0;
 }

Modified: trunk/pkcs11/ssh-agent/gck-ssh-agent.c
==============================================================================
--- trunk/pkcs11/ssh-agent/gck-ssh-agent.c	(original)
+++ trunk/pkcs11/ssh-agent/gck-ssh-agent.c	Tue Jan  6 03:13:26 2009
@@ -43,8 +43,8 @@
 #define socklen_t int
 #endif
 
-/* The PKCS#11 slot we call into */
-static GP11Slot *pkcs11_slot = NULL;
+/* The loaded PKCS#11 module */
+static GP11Module *pkcs11_module = NULL;
 
 static gboolean
 read_all (int fd, guchar *buf, int len)
@@ -125,15 +125,13 @@
 static gpointer
 run_client_thread (gpointer data)
 {
-	gboolean running = TRUE;
-	GError *error = NULL;
 	gint *socket = data;
 	GckSshAgentCall call;
 	GkrBuffer req;
 	GkrBuffer resp;
 	guchar op;
 	
-	g_assert (pkcs11_slot);
+	g_assert (GP11_IS_MODULE (pkcs11_module));
 	
 	memset (&call, 0, sizeof (call));
 	call.sock = g_atomic_int_get (socket);
@@ -143,16 +141,9 @@
 	gkr_buffer_init_full (&resp, 128, (GkrBufferAllocator)g_realloc);
 	call.req = &req;
 	call.resp = &resp;
-	
-	/* Try to open a session for this thread */
-	call.session = gp11_slot_open_session (pkcs11_slot, CKF_SERIAL_SESSION, &error);
-	if (!call.session) {
-		g_warning ("couldn't open pkcs#11 session for agent thread: %s", error->message);
-		g_clear_error (&error);
-		running = FALSE;
-	}
+	call.module = g_object_ref (pkcs11_module);
 
-	while (running) {
+	for (;;) {
 		
 		gkr_buffer_reset (call.req);
 		
@@ -182,7 +173,8 @@
 	
 	gkr_buffer_uninit (&req);
 	gkr_buffer_uninit (&resp);
-
+	g_object_unref (call.module);
+	
 	close (call.sock);
 	g_atomic_int_set (socket, -1);
 	
@@ -190,35 +182,57 @@
 }
 
 /* --------------------------------------------------------------------------------------
- * MAIN SESSION
+ * SESSION MANAGEMENT
  */
 
 /* The main PKCS#11 session that owns objects, and the mutex/cond for waiting on it */
-static GP11Session *pkcs11_session = NULL;
-static gboolean pkcs11_session_checked = FALSE;
-static GMutex *pkcs11_session_mutex = NULL;
-static GCond *pkcs11_session_cond = NULL;
+static GP11Session *pkcs11_main_session = NULL;
+static gboolean pkcs11_main_checked = FALSE;
+static GMutex *pkcs11_main_mutex = NULL;
+static GCond *pkcs11_main_cond = NULL;
 
 static gboolean
-init_main_session (GP11Slot *slot)
+init_pkcs11 (GP11Module *module)
 {
-	GP11Session *session;
+	GP11Session *session = NULL;
+	GList *slots, *l;
+	GP11Mechanisms *mechs;
 	GError *error = NULL;
 	
-	g_assert (GP11_IS_SLOT (slot));
-
-	/* Load our main session */
-	session = gp11_slot_open_session (slot, CKF_SERIAL_SESSION, &error);
+	g_assert (GP11_IS_MODULE (module));
+	
+	/* Find a good slot for our session keys */
+	slots = gp11_module_get_slots (module, TRUE);
+	for (l = slots; session == NULL && l; l = g_list_next (l)) {
+		
+		/* Check that it has the mechanisms we need */
+		mechs = gp11_slot_get_mechanisms (l->data);
+		if (gp11_mechanisms_check (mechs, CKM_RSA_PKCS, CKM_DSA, GP11_INVALID)) {
+
+			/* Try and open a session */
+			session = gp11_slot_open_session (l->data, CKF_SERIAL_SESSION, &error);
+			if (!session) {
+				g_warning ("couldn't create pkcs#11 session: %s", error->message);
+				g_clear_error (&error);
+			}
+		}
+		
+		gp11_mechanisms_free (mechs);
+	}
+	
+	gp11_list_unref_free (slots);
+	
 	if (!session) {
-		g_warning ("couldn't create pkcs#11 session: %s", error->message);
-		g_clear_error (&error);
+		g_warning ("couldn't select a usable pkcs#11 slot for the ssh agent to use");
 		return FALSE;
 	}
 
-	pkcs11_session_mutex = g_mutex_new ();
-	pkcs11_session_cond = g_cond_new ();
-	pkcs11_session_checked = FALSE;
-	pkcs11_session = session;
+	pkcs11_module = g_object_ref (module);
+	
+	pkcs11_main_mutex = g_mutex_new ();
+	pkcs11_main_cond = g_cond_new ();
+	pkcs11_main_checked = FALSE;
+	pkcs11_main_session = session;
 	
 	return TRUE;
 }
@@ -228,15 +242,15 @@
 {
 	GP11Session *result;
 	
-	g_mutex_lock (pkcs11_session_mutex);
+	g_mutex_lock (pkcs11_main_mutex);
 	
-		g_assert (GP11_IS_SESSION (pkcs11_session));
-		while (pkcs11_session_checked)
-			g_cond_wait (pkcs11_session_cond, pkcs11_session_mutex);
-		pkcs11_session_checked = TRUE;
-		result = g_object_ref (pkcs11_session);
+		g_assert (GP11_IS_SESSION (pkcs11_main_session));
+		while (pkcs11_main_checked)
+			g_cond_wait (pkcs11_main_cond, pkcs11_main_mutex);
+		pkcs11_main_checked = TRUE;
+		result = g_object_ref (pkcs11_main_session);
 	
-	g_mutex_unlock (pkcs11_session_mutex);
+	g_mutex_unlock (pkcs11_main_mutex);
 	
 	return result;
 }
@@ -246,35 +260,38 @@
 {
 	g_assert (GP11_IS_SESSION (session));
 	
-	g_mutex_lock (pkcs11_session_mutex);
+	g_mutex_lock (pkcs11_main_mutex);
 	
-		g_assert (session == pkcs11_session);
-		g_assert (pkcs11_session_checked);
+		g_assert (session == pkcs11_main_session);
+		g_assert (pkcs11_main_checked);
 		
 		g_object_unref (session);
-		pkcs11_session_checked = FALSE;
-		g_cond_signal (pkcs11_session_cond);
+		pkcs11_main_checked = FALSE;
+		g_cond_signal (pkcs11_main_cond);
 		
-	g_mutex_unlock (pkcs11_session_mutex);
+	g_mutex_unlock (pkcs11_main_mutex);
 }
 
 static void
-uninit_main_session (void)
+uninit_pkcs11 (void)
 {
 	gboolean ret;
 	
-	g_assert (pkcs11_session_mutex);
-	ret = g_mutex_trylock (pkcs11_session_mutex);
+	g_assert (pkcs11_main_mutex);
+	ret = g_mutex_trylock (pkcs11_main_mutex);
 	g_assert (ret);
 
-		g_assert (GP11_IS_SESSION (pkcs11_session));
-		g_assert (!pkcs11_session_checked);
-		g_object_unref (pkcs11_session);
-		pkcs11_session = NULL;
-		
-	g_mutex_unlock (pkcs11_session_mutex);
-	g_mutex_free (pkcs11_session_mutex);
-	g_cond_free (pkcs11_session_cond);		
+		g_assert (GP11_IS_SESSION (pkcs11_main_session));
+		g_assert (!pkcs11_main_checked);
+		g_object_unref (pkcs11_main_session);
+		pkcs11_main_session = NULL;
+		
+	g_mutex_unlock (pkcs11_main_mutex);
+	g_mutex_free (pkcs11_main_mutex);
+	g_cond_free (pkcs11_main_cond);
+	
+	g_assert (pkcs11_module);
+	g_object_unref (pkcs11_module);
 }
 
 /* --------------------------------------------------------------------------------------
@@ -295,18 +312,6 @@
 /* The path of the socket listening on */
 static char socket_path[1024] = { 0, };
 
-int
-gck_ssh_agent_get_socket_fd (void)
-{
-	return socket_fd;
-}
-
-const gchar*
-gck_ssh_agent_get_socket_path (void)
-{
-	return socket_path;
-}
-
 void
 gck_ssh_agent_accept (void)
 {
@@ -381,20 +386,33 @@
 	g_list_free (socket_clients);
 	socket_clients = NULL;
 	
-	uninit_main_session ();
+	uninit_pkcs11 ();
+}
+
+int
+gck_ssh_agent_initialize (const gchar *prefix, CK_FUNCTION_LIST_PTR funcs)
+{
+	GP11Module *module;
+	int sock;
+	
+	g_return_val_if_fail (funcs, -1);
+	g_return_val_if_fail (prefix, -1);
+	
+	module = gp11_module_new (funcs);
+	sock = gck_ssh_agent_initialize_with_module (prefix, module);
+	g_object_unref (module);
 	
-	g_object_unref (pkcs11_slot);
-	pkcs11_slot = NULL;
+	return sock;
 }
 
-gboolean
-gck_ssh_agent_initialize (const gchar *prefix, GP11Slot *slot)
+int 
+gck_ssh_agent_initialize_with_module (const gchar *prefix, GP11Module *module)
 {
 	struct sockaddr_un addr;
 	int sock;
 	
-	g_return_val_if_fail (GP11_IS_SLOT (slot), FALSE);
-	g_return_val_if_fail (prefix, FALSE);
+	g_return_val_if_fail (prefix, -1);
+	g_return_val_if_fail (GP11_IS_MODULE (module), -1);
 	
 	snprintf (socket_path, sizeof (socket_path), "%s.ssh", prefix);
 	unlink (socket_path);
@@ -402,7 +420,7 @@
 	sock = socket (AF_UNIX, SOCK_STREAM, 0);
 	if (sock < 0) {
 		g_warning ("couldn't create socket: %s", g_strerror (errno));
-		return FALSE;
+		return -1;
 	}
 	
 	memset(&addr, 0, sizeof(addr));
@@ -411,22 +429,23 @@
 	if (bind (sock, (struct sockaddr *) & addr, sizeof (addr)) < 0) {
 		g_warning ("couldn't bind to socket: %s: %s", socket_path, g_strerror (errno));
 		close (sock);
-		return FALSE;
+		return -1;
 	}
 	
 	if (listen (sock, 128) < 0) {
 		g_warning ("couldn't listen on socket: %s", g_strerror (errno));
 		close (sock);
-		return FALSE;
+		return -1;
 	}
 	
 	/* Load our main session */
-	if (!init_main_session (slot)) {
+	if (!init_pkcs11 (module)) {
 		close (sock);
-		return FALSE;
+		return -1;
 	}
 	
-	pkcs11_slot = g_object_ref (slot);
+	g_setenv ("SSH_AUTH_SOCK", socket_path, TRUE);
+	
 	socket_fd = sock;
-	return TRUE;
+	return sock;
 }

Modified: trunk/pkcs11/ssh-agent/gck-ssh-agent.h
==============================================================================
--- trunk/pkcs11/ssh-agent/gck-ssh-agent.h	(original)
+++ trunk/pkcs11/ssh-agent/gck-ssh-agent.h	Tue Jan  6 03:13:26 2009
@@ -3,13 +3,9 @@
 
 #include <glib.h>
 
-#include "gp11/gp11.h"
+#include "pkcs11/pkcs11.h"
 
-gboolean          gck_ssh_agent_initialize              (const gchar *prefix, GP11Slot *slot);
-
-int               gck_ssh_agent_get_socket_fd           (void);
-
-const gchar*      gck_ssh_agent_get_socket_path         (void);
+int               gck_ssh_agent_initialize              (const gchar *prefix, CK_FUNCTION_LIST_PTR funcs);
 
 void              gck_ssh_agent_accept                  (void);
 



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