im.pidgin.pidgin: 3cec6952fcadbd73dddc4c009e798b6fb1789a5b
evands at pidgin.im
evands at pidgin.im
Mon Dec 17 21:35:43 EST 2007
-----------------------------------------------------------------
Revision: 3cec6952fcadbd73dddc4c009e798b6fb1789a5b
Ancestor: 33785a8c844de496aeeed927bad8b39a6e091931
Author: evands at pidgin.im
Date: 2007-12-17T23:22:30
Branch: im.pidgin.pidgin
Modified files:
libpurple/protocols/jabber/auth.c
ChangeLog:
Added support for authentication via CRAM-MD5 when using jabber:iq:auth.
This, combined with 33785a8c844de496aeeed927bad8b39a6e091931, fixes connectivity with iChat Server 10.5 (a jabberd derivative with SASL support), among other servers, when libpurple is compiled with SASL support.
-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/auth.c 58c06037df664e395e94097daf51b2695e251470
+++ libpurple/protocols/jabber/auth.c a4c3673cdf3aaba368ea3fa8aaf4206452f3f7f2
@@ -570,6 +570,75 @@ static void auth_old_result_cb(JabberStr
}
}
+/*!
+ * @brief Given the server challenge (message) and the key (password), calculate the HMAC-MD5 digest
+ *
+ * This is the crammd5 response. Inspired by cyrus-sasl's _sasl_hmac_md5()
+ */
+static void
+auth_hmac_md5(const char *challenge, size_t challenge_len, const char *key, size_t key_len, guchar *digest)
+{
+ PurpleCipher *cipher;
+ PurpleCipherContext *context;
+ int i;
+ /* inner padding - key XORd with ipad */
+ unsigned char k_ipad[65];
+ /* outer padding - key XORd with opad */
+ unsigned char k_opad[65];
+
+ cipher = purple_ciphers_find_cipher("md5");
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (strlen(key) > 64) {
+ guchar keydigest[16];
+
+ context = purple_cipher_context_new(cipher, NULL);
+ purple_cipher_context_append(context, (const guchar *)key, strlen(key));
+ purple_cipher_context_digest(context, 16, keydigest, NULL);
+ purple_cipher_context_destroy(context);
+
+ key = (char *)keydigest;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ memset(k_ipad, '\0', sizeof k_ipad);
+ memset(k_opad, '\0', sizeof k_opad);
+ memcpy(k_ipad, (void *)key, key_len);
+ memcpy(k_opad, (void *)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner MD5 */
+ context = purple_cipher_context_new(cipher, NULL);
+ purple_cipher_context_append(context, k_ipad, 64); /* start with inner pad */
+ purple_cipher_context_append(context, (const guchar *)challenge, challenge_len); /* then text of datagram */
+ purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 1st pass */
+ purple_cipher_context_destroy(context);
+
+ /* perform outer MD5 */
+ context = purple_cipher_context_new(cipher, NULL);
+ purple_cipher_context_append(context, k_opad, 64); /* start with outer pad */
+ purple_cipher_context_append(context, digest, 16); /* then results of 1st hash */
+ purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 2nd pass */
+ purple_cipher_context_destroy(context);
+}
+
static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data)
{
JabberIq *iq;
@@ -615,6 +684,33 @@ static void auth_old_cb(JabberStream *js
jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
jabber_iq_send(iq);
+ } else if(js->stream_id && xmlnode_get_child(query, "crammd5")) {
+ const char *challenge;
+ guchar digest[16];
+ char h[17], *p;
+ int i;
+
+ iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
+ query = xmlnode_get_child(iq->node, "query");
+
+ x = xmlnode_new_child(query, "username");
+ xmlnode_insert_data(x, js->user->node, -1);
+ x = xmlnode_new_child(query, "resource");
+ xmlnode_insert_data(x, js->user->resource, -1);
+
+ x = xmlnode_new_child(query, "crammd5");
+ challenge = xmlnode_get_attrib(xmlnode_get_child(query, "crammd5"), "challenge");
+ auth_hmac_md5(challenge, strlen(challenge), pw, strlen(pw), &digest);
+
+ /* Translate the digest to a hexadecimal notation */
+ p = h;
+ for(i=0; i<16; i++, p+=2)
+ snprintf(p, 3, "%02x", digest[i]);
+ xmlnode_insert_data(x, h, -1);
+
+ jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
+ jabber_iq_send(iq);
+
} else if(xmlnode_get_child(query, "password")) {
if(js->gsc == NULL && !purple_account_get_bool(js->gc->account,
"auth_plain_in_clear", FALSE)) {
More information about the Commits
mailing list