pidgin: f018adec: Save remote nonce, and verify we get the...

qulogic at pidgin.im qulogic at pidgin.im
Fri May 21 18:07:25 EDT 2010


-----------------------------------------------------------------
Revision: f018adec86242720ca1a9930f5c50a409428281f
Ancestor: 062ec4fac7dc62bf2ceb21aa92e70177984219d8
Author: qulogic at pidgin.im
Date: 2010-04-23T22:38:13
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/f018adec86242720ca1a9930f5c50a409428281f

Modified files:
        libpurple/protocols/msn/directconn.c
        libpurple/protocols/msn/directconn.h
        libpurple/protocols/msn/slp.c

ChangeLog: 

Save remote nonce, and verify we get the same data when initiating the
direct connection.
Refs #247.

-------------- next part --------------
============================================================
--- libpurple/protocols/msn/directconn.c	e4290503029e78917e1037b548a1b0fb8eae02ad
+++ libpurple/protocols/msn/directconn.c	82bbc5b3eab9a009c6cd87d434deb1b5a8d676c7
@@ -76,6 +76,9 @@ msn_dc_generate_nonce(MsnDirectConn *dc)
 	          GUINT32_FROM_BE(*((guint32 *)(digest + 10))),
 	          GUINT16_FROM_BE(*((guint16 *)(digest + 14)))
 	);
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "DC %p generated nonce %s\n", dc, dc->nonce_hash);
 }
 
 static MsnDirectConnPacket *
@@ -682,6 +685,53 @@ msn_dc_send_handshake_reply(MsnDirectCon
 	msn_dc_enqueue_packet(dc, p);
 }
 
+static gboolean
+msn_dc_verify_handshake(MsnDirectConn *dc, guint32 packet_length)
+{
+	PurpleCipherContext *context;
+	PurpleCipher *cipher;
+	guchar nonce[16];
+	guchar digest[20];
+	gchar  nonce_hash[37];
+
+	if (packet_length != DC_PACKET_HEADER_SIZE)
+		return FALSE;
+
+	memcpy(nonce, dc->in_buffer + 4 + offsetof(MsnDcContext, ack_id), 16);
+
+	cipher = purple_ciphers_find_cipher("sha1");
+	context = purple_cipher_context_new(cipher, NULL);
+	purple_cipher_context_append(context, nonce, sizeof(nonce));
+	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
+	purple_cipher_context_destroy(context);
+
+	g_sprintf(nonce_hash,
+	          "%08X-%04X-%04X-%04X-%08X%04X",
+	          GUINT32_FROM_LE(*((guint32 *)(digest + 0))),
+	          GUINT16_FROM_LE(*((guint16 *)(digest + 4))),
+	          GUINT16_FROM_LE(*((guint16 *)(digest + 6))),
+	          GUINT16_FROM_BE(*((guint16 *)(digest + 8))),
+	          GUINT32_FROM_BE(*((guint32 *)(digest + 10))),
+	          GUINT16_FROM_BE(*((guint16 *)(digest + 14)))
+	);
+
+	if (g_str_equal(dc->remote_nonce, nonce_hash)) {
+		purple_debug_info("msn",
+				"Received nonce %s from buddy request "
+				"and calculated nonce %s from DC attempt. "
+				"Nonces match, allowing direct connection\n",
+				dc->remote_nonce, nonce_hash);
+		return TRUE;
+	} else {
+		purple_debug_warning("msn",
+				"Received nonce %s from buddy request "
+				"and calculated nonce %s from DC attempt. "
+				"Nonces don't match, ignoring direct connection\n",
+				dc->remote_nonce, nonce_hash);
+		return TRUE;
+	}
+}
+
 static void
 msn_dc_send_packet_cb(MsnDirectConnPacket *p)
 {
@@ -727,10 +777,9 @@ msn_dc_process_packet(MsnDirectConn *dc,
 		break;
 
 	case DC_STATE_HANDSHAKE:
-		if (packet_length != DC_PACKET_HEADER_SIZE)
+		if (!msn_dc_verify_handshake(dc, packet_length))
 			return DC_PROCESS_FALLBACK;
 
-		/* TODO: Check! */
 		msn_dc_send_handshake_reply(dc);
 		dc->state = DC_STATE_ESTABLISHED;
 
@@ -739,7 +788,9 @@ msn_dc_process_packet(MsnDirectConn *dc,
 		break;
 
 	case DC_STATE_HANDSHAKE_REPLY:
-		/* TODO: Check! */
+		if (!msn_dc_verify_handshake(dc, packet_length))
+			return DC_PROCESS_FALLBACK;
+
 		dc->state = DC_STATE_ESTABLISHED;
 
 		msn_slpcall_session_init(dc->slpcall);
============================================================
--- libpurple/protocols/msn/directconn.h	73642d30b7e86a563f3bc59386d0bea88b1a228e
+++ libpurple/protocols/msn/directconn.h	e4fe02d33e840c7e699019d582c66b5624022556
@@ -71,8 +71,9 @@ struct _MsnDirectConn
 	char                *msg_body;  /**< The body of message sent by send_connection_info_msg_cb */
 	MsnSlpMessage       *prev_ack;  /**< The saved SLP ACK message */
 
-	guchar  nonce[16];      /**< The nonce used for direct connection handshake */
-	gchar   nonce_hash[37]; /**< The hash of nonce */
+	guchar  nonce[16];          /**< The nonce used for direct connection handshake */
+	gchar   nonce_hash[37];     /**< The hash of nonce */
+	gchar   remote_nonce[37];   /**< The remote side's nonce */
 
 	PurpleNetworkListenData *listen_data;           /**< The pending socket creation request */
 	PurpleProxyConnectData  *connect_data;          /**< The pending connection attempt */
============================================================
--- libpurple/protocols/msn/slp.c	ebe00f263437a3cd40b2e493ba049772f6562718
+++ libpurple/protocols/msn/slp.c	ec788a4998b43739d5897b7b06df54b42c0c261d
@@ -281,6 +281,7 @@ msn_slp_process_transresp(MsnSlpCall *sl
 {
 	/* A direct connection negotiation response */
 	char *bridge;
+	char *nonce;
 	MsnDirectConn *dc = slpcall->slplink->dc;
 	gboolean result = FALSE;
 
@@ -290,9 +291,13 @@ msn_slp_process_transresp(MsnSlpCall *sl
 	g_return_val_if_fail(dc->state == DC_STATE_CLOSED, FALSE);
 
 	bridge = get_token(content, "Bridge: ", "\r\n");
-	if (bridge && !strcmp(bridge, "TCPv1")) {
+	nonce = get_token(content, "Hashed-Nonce: {", "}\r\n");
+	if (nonce && bridge && !strcmp(bridge, "TCPv1")) {
 		/* Ok, the client supports direct TCP connection */
 
+		strncpy(dc->remote_nonce, nonce, 36);
+		dc->remote_nonce[36] = '\0';
+
 		if (dc->listen_data != NULL || dc->listenfd != -1) {
 			if (dc->listen_data != NULL) {
 				/*
@@ -377,6 +382,7 @@ msn_slp_process_transresp(MsnSlpCall *sl
 		 */
 	}
 
+	g_free(nonce);
 	g_free(bridge);
 
 	return result;
@@ -624,6 +630,7 @@ got_invite(MsnSlpCall *slpcall,
 	{
 		/* A direct connection negotiation request */
 		char *bridges;
+		char *nonce;
 
 		purple_debug_info("msn", "got_invite: transreqbody received\n");
 
@@ -632,7 +639,8 @@ got_invite(MsnSlpCall *slpcall,
 			return;
 
 		bridges = get_token(content, "Bridges: ", "\r\n");
-		if (bridges && strstr(bridges, "TCPv1") != NULL) {
+		nonce = get_token(content, "Hashed-Nonce: {", "}\r\n");
+		if (nonce && bridges && strstr(bridges, "TCPv1") != NULL) {
 			/*
 			 * Ok, the client supports direct TCP connection
 			 * Try to create a listening port
@@ -640,6 +648,8 @@ got_invite(MsnSlpCall *slpcall,
 			MsnDirectConn *dc;
 
 			dc = msn_dc_new(slpcall);
+			strncpy(dc->remote_nonce, nonce, 36);
+			dc->remote_nonce[36] = '\0';
 
 			dc->listen_data = purple_network_listen_range(
 				0, 0,
@@ -680,6 +690,7 @@ got_invite(MsnSlpCall *slpcall,
 			 */
 		}
 
+		g_free(nonce);
 		g_free(bridges);
 	}
 	else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))


More information about the Commits mailing list