libpurple/protocols/msn/directconn.c

changeset 30090
a97b8c06eeae
parent 30086
32109706f5ec
child 30092
ad8776ef2844
--- a/libpurple/protocols/msn/directconn.c	Fri Apr 23 22:19:23 2010 +0000
+++ b/libpurple/protocols/msn/directconn.c	Fri Apr 23 22:38:13 2010 +0000
@@ -76,6 +76,9 @@
 	          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_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 @@
 		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 @@
 		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);

mercurial