comparison libpurple/protocols/jabber/auth.c @ 23266:2b997b690500

A patch from QuLogic to eliminate duplicated HMAC-MD5 code in the Jabber prpl by using the cipher API. Fixes #5976 committer: Richard Laager <rlaager@wiktel.com>
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Mon, 02 Jun 2008 05:06:58 +0000
parents 73b86c478d37
children 5c70d953a497
comparison
equal deleted inserted replaced
23265:6c4db8059e91 23266:2b997b690500
587 purple_connection_error_reason (js->gc, reason, msg); 587 purple_connection_error_reason (js->gc, reason, msg);
588 g_free(msg); 588 g_free(msg);
589 } 589 }
590 } 590 }
591 591
592 /*!
593 * @brief Given the server challenge (message) and the key (password), calculate the HMAC-MD5 digest
594 *
595 * This is the crammd5 response. Inspired by cyrus-sasl's _sasl_hmac_md5()
596 */
597 static void
598 auth_hmac_md5(const char *challenge, size_t challenge_len, const char *key, size_t key_len, guchar *digest)
599 {
600 PurpleCipher *cipher;
601 PurpleCipherContext *context;
602 int i;
603 /* inner padding - key XORd with ipad */
604 unsigned char k_ipad[65];
605 /* outer padding - key XORd with opad */
606 unsigned char k_opad[65];
607
608 cipher = purple_ciphers_find_cipher("md5");
609
610 /* if key is longer than 64 bytes reset it to key=MD5(key) */
611 if (strlen(key) > 64) {
612 guchar keydigest[16];
613
614 context = purple_cipher_context_new(cipher, NULL);
615 purple_cipher_context_append(context, (const guchar *)key, strlen(key));
616 purple_cipher_context_digest(context, 16, keydigest, NULL);
617 purple_cipher_context_destroy(context);
618
619 key = (char *)keydigest;
620 key_len = 16;
621 }
622
623 /*
624 * the HMAC_MD5 transform looks like:
625 *
626 * MD5(K XOR opad, MD5(K XOR ipad, text))
627 *
628 * where K is an n byte key
629 * ipad is the byte 0x36 repeated 64 times
630 * opad is the byte 0x5c repeated 64 times
631 * and text is the data being protected
632 */
633
634 /* start out by storing key in pads */
635 memset(k_ipad, '\0', sizeof k_ipad);
636 memset(k_opad, '\0', sizeof k_opad);
637 memcpy(k_ipad, (void *)key, key_len);
638 memcpy(k_opad, (void *)key, key_len);
639
640 /* XOR key with ipad and opad values */
641 for (i=0; i<64; i++) {
642 k_ipad[i] ^= 0x36;
643 k_opad[i] ^= 0x5c;
644 }
645
646 /* perform inner MD5 */
647 context = purple_cipher_context_new(cipher, NULL);
648 purple_cipher_context_append(context, k_ipad, 64); /* start with inner pad */
649 purple_cipher_context_append(context, (const guchar *)challenge, challenge_len); /* then text of datagram */
650 purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 1st pass */
651 purple_cipher_context_destroy(context);
652
653 /* perform outer MD5 */
654 context = purple_cipher_context_new(cipher, NULL);
655 purple_cipher_context_append(context, k_opad, 64); /* start with outer pad */
656 purple_cipher_context_append(context, digest, 16); /* then results of 1st hash */
657 purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 2nd pass */
658 purple_cipher_context_destroy(context);
659 }
660
661 static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data) 592 static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data)
662 { 593 {
663 JabberIq *iq; 594 JabberIq *iq;
664 xmlnode *query, *x; 595 xmlnode *query, *x;
665 const char *type = xmlnode_get_attrib(packet, "type"); 596 const char *type = xmlnode_get_attrib(packet, "type");
701 xmlnode_insert_data(x, h, -1); 632 xmlnode_insert_data(x, h, -1);
702 g_free(s); 633 g_free(s);
703 jabber_iq_set_callback(iq, auth_old_result_cb, NULL); 634 jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
704 jabber_iq_send(iq); 635 jabber_iq_send(iq);
705 636
706 } else if(js->stream_id && xmlnode_get_child(query, "crammd5")) { 637 } else if(js->stream_id && (x = xmlnode_get_child(query, "crammd5"))) {
707 const char *challenge; 638 const char *challenge;
708 guchar digest[16]; 639 gchar digest[33];
709 char h[33], *p; 640 PurpleCipherContext *hmac;
710 int i; 641
711 642 /* Calculate the MHAC-MD5 digest */
712 challenge = xmlnode_get_attrib(xmlnode_get_child(query, "crammd5"), "challenge"); 643 challenge = xmlnode_get_attrib(x, "challenge");
713 auth_hmac_md5(challenge, strlen(challenge), pw, strlen(pw), digest); 644 hmac = purple_cipher_context_new_by_name("hmac", NULL);
645 purple_cipher_context_set_option(hmac, "hash", "md5");
646 purple_cipher_context_set_key(hmac, (guchar *)pw);
647 purple_cipher_context_append(hmac, (guchar *)challenge, strlen(challenge));
648 purple_cipher_context_digest_to_str(hmac, 33, digest, NULL);
649 purple_cipher_context_destroy(hmac);
714 650
715 /* Create the response query */ 651 /* Create the response query */
716 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth"); 652 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
717 query = xmlnode_get_child(iq->node, "query"); 653 query = xmlnode_get_child(iq->node, "query");
718 654
721 x = xmlnode_new_child(query, "resource"); 657 x = xmlnode_new_child(query, "resource");
722 xmlnode_insert_data(x, js->user->resource, -1); 658 xmlnode_insert_data(x, js->user->resource, -1);
723 659
724 x = xmlnode_new_child(query, "crammd5"); 660 x = xmlnode_new_child(query, "crammd5");
725 661
726 /* Translate the digest to a hexadecimal notation */ 662 xmlnode_insert_data(x, digest, 32);
727 p = h;
728 for(i=0; i<16; i++, p+=2)
729 snprintf(p, 3, "%02x", digest[i]);
730 xmlnode_insert_data(x, h, -1);
731 663
732 jabber_iq_set_callback(iq, auth_old_result_cb, NULL); 664 jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
733 jabber_iq_send(iq); 665 jabber_iq_send(iq);
734 666
735 } else if(xmlnode_get_child(query, "password")) { 667 } else if(xmlnode_get_child(query, "password")) {