diff libpurple/protocols/jabber/auth_scram.c @ 28717:464d022d7d6e

jabber: Add SASLprep and the username substitution called for in draft-ietf-sasl-scram-10 5.1. The non-libidn code has not been tested.
author Paul Aurich <paul@darkrain42.org>
date Mon, 30 Nov 2009 20:34:54 +0000
parents cea22db36ffc
children f10741a709a9
line wrap: on
line diff
--- a/libpurple/protocols/jabber/auth_scram.c	Mon Nov 30 02:44:03 2009 +0000
+++ b/libpurple/protocols/jabber/auth_scram.c	Mon Nov 30 20:34:54 2009 +0000
@@ -181,7 +181,10 @@
 	data->server_signature->len = hash_len;
 
 	salted_password = jabber_scram_hi(data->hash, pass, salt, iterations);
+
+	memset(pass->str, 0, pass->allocated_len);
 	g_string_free(pass, TRUE);
+
 	if (!salted_password)
 		return FALSE;
 
@@ -358,6 +361,25 @@
 	return TRUE;
 }
 
+static gchar *escape_username(const gchar *in)
+{
+	GString *s = g_string_new(in);
+	gchar *c;
+	gsize i = 0;
+
+	c = s->str;
+	while (*c) {
+		if (*c == ',' || *c == '=') {
+			g_string_erase(s, i, 1);
+			g_string_insert(s, i, *c == ',' ? "=2C" : "=3D");
+		}
+
+		++c; ++i;
+	}
+
+	return g_string_free(s, FALSE);
+}
+
 static xmlnode *scram_start(JabberStream *js, xmlnode *mechanisms)
 {
 	xmlnode *reply;
@@ -367,10 +389,28 @@
 	gboolean binding_supported = TRUE;
 #endif
 	gchar *dec_out, *enc_out;
+	gchar *prepped_node, *tmp;
+	gchar *prepped_pass;
+
+	prepped_node = jabber_saslprep(js->user->node);
+	if (!prepped_node) {
+		/* TODO: Error handling in the response value from scram_start */
+		return NULL;
+	}
+
+	tmp = escape_username(prepped_node);
+	g_free(prepped_node);
+	prepped_node = tmp;
+
+	prepped_pass = jabber_saslprep(purple_connection_get_password(js->gc));
+	if (!prepped_pass) {
+		g_free(prepped_node);
+		return NULL;
+	}
 
 	data = js->auth_mech_data = g_new0(JabberScramData, 1);
 	data->hash = mech_to_hash(js->auth_mech->name);
-	data->password = purple_connection_get_password(js->gc);
+	data->password = prepped_pass;
 
 #ifdef CHANNEL_BINDING
 	if (strstr(js->auth_mech_name, "-PLUS"))
@@ -381,8 +421,8 @@
 
 	data->auth_message = g_string_new(NULL);
 	g_string_printf(data->auth_message, "n=%s,r=%s",
-			js->user->node /* TODO: SaslPrep */,
-			data->cnonce);
+			prepped_node, data->cnonce);
+	g_free(prepped_node);
 
 	data->step = 1;
 
@@ -500,6 +540,11 @@
 		g_string_free(data->client_proof, TRUE);
 	if (data->server_signature)
 		g_string_free(data->server_signature, TRUE);
+	if (data->password) {
+		memset(data->password, 0, strlen(data->password));
+		g_free(data->password);
+	}
+
 	g_free(data);
 }