changeset 29630:9f59abd49def

jabber: Validate the hash on incoming BoB objects (in case the CID is on the form algo+hash@bob.xmpp.org).
author Marcus Lundblad <ml@update.uu.se>
date Mon, 22 Mar 2010 21:34:17 +0000
parents ffb8cd9fb528
children e3eda7aa0653 f14cbb6a28a7
files ChangeLog libpurple/protocols/jabber/auth.c libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/data.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jutil.c libpurple/protocols/jabber/jutil.h libpurple/protocols/jabber/message.c libpurple/protocols/jabber/presence.c libpurple/protocols/jabber/si.c libpurple/protocols/jabber/useravatar.c
diffstat 11 files changed, 100 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Mar 22 20:15:55 2010 +0000
+++ b/ChangeLog	Mon Mar 22 21:34:17 2010 +0000
@@ -55,6 +55,7 @@
 	  rjoly for testing)
 	* When sending data using in-band-bytestreams, interpret the block-size
 	  attribute as the size of the BASE64-encoded representation of the data.
+	* Validate the hash on incoming BoB data objects (for custom smileys etc.).
 
 	Yahoo:
 	* Attempt to better handle transparent proxies interfering with HTTP-based
--- a/libpurple/protocols/jabber/auth.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/auth.c	Mon Mar 22 21:34:17 2010 +0000
@@ -287,7 +287,7 @@
 
 			x = xmlnode_new_child(query, "digest");
 			s = g_strdup_printf("%s%s", js->stream_id, pw);
-			hash = jabber_calculate_data_sha1sum(s, strlen(s));
+			hash = jabber_calculate_data_hash(s, strlen(s), "sha1");
 			xmlnode_insert_data(x, hash, -1);
 			g_free(hash);
 			g_free(s);
--- a/libpurple/protocols/jabber/buddy.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Mon Mar 22 21:34:17 2010 +0000
@@ -516,7 +516,8 @@
 		binval = xmlnode_new_child(photo, "BINVAL");
 		enc = purple_base64_encode(avatar_data, avatar_len);
 
-		js->avatar_hash = jabber_calculate_data_sha1sum(avatar_data, avatar_len);
+		js->avatar_hash =
+			jabber_calculate_data_hash(avatar_data, avatar_len, "sha1");
 
 		xmlnode_insert_data(binval, enc, -1);
 		g_free(enc);
@@ -936,7 +937,7 @@
 			g_free(bintext);
 
 			if (data) {
-				vcard_hash = jabber_calculate_data_sha1sum(data, size);
+				vcard_hash = jabber_calculate_data_hash(data, size, "sha1");
 				g_free(data);
 			}
 		}
@@ -1185,7 +1186,7 @@
 
 						purple_notify_user_info_add_pair(user_info, (photo ? _("Photo") : _("Logo")), img_text);
 
-						hash = jabber_calculate_data_sha1sum(data, size);
+						hash = jabber_calculate_data_hash(data, size, "sha1");
 						purple_buddy_icons_set_for_user(account, bare_jid, data, size, hash);
 						g_free(hash);
 						g_free(img_text);
--- a/libpurple/protocols/jabber/data.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/data.c	Mon Mar 22 21:34:17 2010 +0000
@@ -39,7 +39,7 @@
 	JabberStream *js)
 {
 	JabberData *data = g_new0(JabberData, 1);
-	gchar *checksum = jabber_calculate_data_sha1sum(rawdata, size);
+	gchar *checksum = jabber_calculate_data_hash(rawdata, size, "sha1");
 	gchar cid[256];
 
 	g_snprintf(cid, sizeof(cid), "sha1+%s@bob.xmpp.org", checksum);
@@ -54,6 +54,69 @@
 	return data;
 }
 
+
+static gboolean
+jabber_data_has_valid_hash(const JabberData *data)
+{
+	const gchar *cid = jabber_data_get_cid(data);
+	gchar **cid_parts = g_strsplit(cid, "@", -1);
+	gchar **iter;
+	int num_parts = 0;
+
+	purple_debug_info("jabber", "validating BoB hash %s\n", cid);
+	
+	for (iter = cid_parts; *iter != NULL ; iter++) {
+		num_parts++;
+	}
+
+	if (num_parts == 2 && purple_strequal(cid_parts[1], "bob.xmpp.org")) {
+		gchar **sub_parts = g_strsplit(cid_parts[0], "+", -1);
+
+		num_parts = 0;
+		for (iter = sub_parts ; *iter != NULL ; iter++) {
+			num_parts++;
+		}
+
+		if (num_parts == 2) {
+			const gchar *hash_algo = sub_parts[0];
+			const gchar *hash_value = sub_parts[1];
+			gchar *digest =
+				jabber_calculate_data_hash(jabber_data_get_data(data),
+				    jabber_data_get_size(data), hash_algo);
+
+			purple_debug_info("jabber", "BoB expecting hash: %s\n", digest);
+			
+			if (digest) {
+				gboolean result = purple_strequal(digest, hash_value);
+
+				if (!result) {
+					purple_debug_error("jabber", "invalid BoB hash\n");
+				}
+				g_free(digest);
+				return result;
+			} else {
+				purple_debug_info("jabber", "unknown BoB hash algo\n");
+				return FALSE;
+			}
+		} else {
+			return TRUE;
+		}
+	} else {
+		return TRUE;
+	}
+}
+
+static void
+jabber_data_delete(gpointer cbdata)
+{
+	JabberData *data = cbdata;
+	g_free(data->cid);
+	g_free(data->type);
+	g_free(data->data);
+	g_free(data);
+}
+
+
 JabberData *
 jabber_data_create_from_xml(xmlnode *tag)
 {
@@ -96,18 +159,12 @@
 	data->cid = g_strdup(cid);
 	data->type = g_strdup(type);
 
-	return data;
-}
-
+	if (!jabber_data_has_valid_hash(data)) {
+		jabber_data_delete(data);
+		return NULL;
+	}
 
-static void
-jabber_data_delete(gpointer cbdata)
-{
-	JabberData *data = cbdata;
-	g_free(data->cid);
-	g_free(data->type);
-	g_free(data->data);
-	g_free(data);
+	return data;
 }
 
 const char *
@@ -205,8 +262,12 @@
 			if (!ephemeral) {
 				jabber_data_associate_remote(data);
 			}
-			/* TODO: validate hash */
 			cb(data, alt, userdata);
+		} else {
+			/* could not validate hash when creating data from XML */
+			purple_debug_info("jabber",
+			    "hash validation failed on requested BoB object\n");
+			cb(NULL, alt, userdata);
 		}
 	} else if (item_not_found) {
 		purple_debug_info("jabber",
--- a/libpurple/protocols/jabber/jabber.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Mar 22 21:34:17 2010 +0000
@@ -980,8 +980,8 @@
 	image = purple_buddy_icons_find_account_icon(account);
 	if (image != NULL) {
 		js->initial_avatar_hash =
-			jabber_calculate_data_sha1sum(purple_imgstore_get_data(image),
-					purple_imgstore_get_size(image));
+			jabber_calculate_data_hash(purple_imgstore_get_data(image),
+					purple_imgstore_get_size(image), "sha1");
 		purple_imgstore_unref(image);
 	}
 
--- a/libpurple/protocols/jabber/jutil.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/jutil.c	Mon Mar 22 21:34:17 2010 +0000
@@ -728,17 +728,17 @@
 	return NULL;
 }
 
-/* The same as purple_util_get_image_checksum, but guaranteed to remain SHA1 */
 char *
-jabber_calculate_data_sha1sum(gconstpointer data, size_t len)
+jabber_calculate_data_hash(gconstpointer data, size_t len, 
+    const gchar *hash_algo)
 {
 	PurpleCipherContext *context;
 	static gchar digest[41];
 
-	context = purple_cipher_context_new_by_name("sha1", NULL);
+	context = purple_cipher_context_new_by_name(hash_algo, NULL);
 	if (context == NULL)
 	{
-		purple_debug_error("jabber", "Could not find sha1 cipher\n");
+		purple_debug_error("jabber", "Could not find %s cipher\n", hash_algo);
 		g_return_val_if_reached(NULL);
 	}
 
@@ -746,7 +746,8 @@
 	purple_cipher_context_append(context, data, len);
 	if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
 	{
-		purple_debug_error("jabber", "Failed to get SHA-1 digest.\n");
+		purple_debug_error("jabber", "Failed to get digest for %s cipher.\n",
+		    hash_algo);
 		g_return_val_if_reached(NULL);
 	}
 	purple_cipher_context_destroy(context);
--- a/libpurple/protocols/jabber/jutil.h	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/jutil.h	Mon Mar 22 21:34:17 2010 +0000
@@ -85,5 +85,6 @@
 /* show attr (presence stanza) -> state */
 JabberBuddyState jabber_buddy_show_get_state(const char *id);
 
-char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len);
+char *jabber_calculate_data_hash(gconstpointer data, size_t len,
+    const gchar *hash_algo);
 #endif /* PURPLE_JABBER_JUTIL_H_ */
--- a/libpurple/protocols/jabber/message.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/message.c	Mon Mar 22 21:34:17 2010 +0000
@@ -474,7 +474,10 @@
 		if (!data && cid != NULL) {
 			/* we haven't cached this already, let's add it */
 			JabberData *new_data = jabber_data_create_from_xml(data_tag);
-			jabber_data_associate_remote(new_data);
+
+			if (new_data) {
+				jabber_data_associate_remote(new_data);
+			}
 		}
 	}
 }
--- a/libpurple/protocols/jabber/presence.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/presence.c	Mon Mar 22 21:34:17 2010 +0000
@@ -457,7 +457,7 @@
 
 			data = purple_base64_decode(text, &size);
 			if (data) {
-				gchar *hash = jabber_calculate_data_sha1sum(data, size);
+				gchar *hash = jabber_calculate_data_hash(data, size, "sha1");
 				purple_buddy_icons_set_for_user(js->gc->account, from, data,
 				                                size, hash);
 				g_free(hash);
--- a/libpurple/protocols/jabber/si.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/si.c	Mon Mar 22 21:34:17 2010 +0000
@@ -289,7 +289,7 @@
 				jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource);
 
 		/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
-		hash = jabber_calculate_data_sha1sum(dstaddr, strlen(dstaddr));
+		hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
 
 		jsx->connect_data = purple_proxy_connect_socks5(NULL, jsx->gpi,
 				hash, 0,
@@ -474,7 +474,7 @@
 			jsx->js->user->resource, xfer->who);
 
 	/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
-	hash = jabber_calculate_data_sha1sum(dstaddr, strlen(dstaddr));
+	hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
 
 	if(strncmp(hash, jsx->rxqueue + 5, 40) ||
 			jsx->rxqueue[45] != 0x00 || jsx->rxqueue[46] != 0x00) {
--- a/libpurple/protocols/jabber/useravatar.c	Mon Mar 22 20:15:55 2010 +0000
+++ b/libpurple/protocols/jabber/useravatar.c	Mon Mar 22 21:34:17 2010 +0000
@@ -149,8 +149,9 @@
 			char *lengthstring, *widthstring, *heightstring;
 
 			/* compute the sha1 hash */
-			char *hash = jabber_calculate_data_sha1sum(purple_imgstore_get_data(img),
-			                                           purple_imgstore_get_size(img));
+			char *hash = jabber_calculate_data_hash(purple_imgstore_get_data(img),
+			                                        purple_imgstore_get_size(img),
+			    									"sha1");
 			char *base64avatar = purple_base64_encode(purple_imgstore_get_data(img),
 			                                          purple_imgstore_get_size(img));