# HG changeset patch # User Marcus Lundblad # Date 1269293657 0 # Node ID 9f59abd49def45e724615a4fdae347db11a6f107 # Parent ffb8cd9fb5282c908f8933c25502aebee4ca2bfc jabber: Validate the hash on incoming BoB objects (in case the CID is on the form algo+hash@bob.xmpp.org). diff -r ffb8cd9fb528 -r 9f59abd49def ChangeLog --- 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 diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/auth.c --- 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); diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/buddy.c --- 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); diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/data.c --- 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", diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/jabber.c --- 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); } diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/jutil.c --- 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); diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/jutil.h --- 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_ */ diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/message.c --- 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); + } } } } diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/presence.c --- 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); diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/si.c --- 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) { diff -r ffb8cd9fb528 -r 9f59abd49def libpurple/protocols/jabber/useravatar.c --- 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));