cpw.darkrain42.xmpp.scram: a6243850: jabber: Add SASLprep and the username su...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Mon Nov 30 15:41:23 EST 2009


-----------------------------------------------------------------
Revision: a6243850821f40a77b12227baeb436de03896abe
Ancestor: 1f735ffef4b424fdc647312c81fea5a83dc22cad
Author: darkrain42 at pidgin.im
Date: 2009-11-30T20:34:54
Branch: im.pidgin.cpw.darkrain42.xmpp.scram
URL: http://d.pidgin.im/viewmtn/revision/info/a6243850821f40a77b12227baeb436de03896abe

Modified files:
        libpurple/protocols/jabber/auth_scram.c
        libpurple/protocols/jabber/auth_scram.h
        libpurple/protocols/jabber/jutil.c
        libpurple/protocols/jabber/jutil.h
        libpurple/tests/test_jabber_scram.c

ChangeLog: 

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.

-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/auth_scram.c	58cb4d7993882757edb91d259b05f2fb44bcff51
+++ libpurple/protocols/jabber/auth_scram.c	3e6bf8ce68e3778cc331cdcb4aa75483001fa53d
@@ -181,7 +181,10 @@ jabber_scram_calc_proofs(JabberScramData
 	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 @@ jabber_scram_feed_parser(JabberScramData
 	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 @@ static xmlnode *scram_start(JabberStream
 	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 @@ static xmlnode *scram_start(JabberStream
 
 	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 @@ void jabber_scram_data_destroy(JabberScr
 		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);
 }
 
============================================================
--- libpurple/protocols/jabber/auth_scram.h	527089bfbf85ffb55506fe4ca292e1bf230bf40c
+++ libpurple/protocols/jabber/auth_scram.h	2ca54ce4052318fbc65cd3802f7fa089c88ba01a
@@ -40,8 +40,8 @@ typedef struct {
 
 	GString *client_proof;
 	GString *server_signature;
-	
-	const gchar *password;
+
+	gchar *password;
 	gboolean channel_binding;
 	int step;
 } JabberScramData;
============================================================
--- libpurple/protocols/jabber/jutil.c	603120abe6629d5e8f9e79d5198134bb252b0875
+++ libpurple/protocols/jabber/jutil.c	d8bcbe586e0ac7c3b8c610001d9641680083a227
@@ -276,6 +276,42 @@ gboolean jabber_resourceprep_validate(co
 #endif /* USE_IDN */
 }
 
+char *jabber_saslprep(const char *in)
+{
+#ifdef USE_IDN
+	char *out;
+
+	g_return_val_if_fail(in != NULL, NULL);
+	g_return_val_if_fail(strlen(in) <= sizeof(idn_buffer) - 1, NULL);
+
+	strncpy(idn_buffer, in, sizeof(idn_buffer) - 1);
+	idn_buffer[sizeof(idn_buffer) - 1] = '\0';
+
+	if (STRINGPREP_OK != stringprep(idn_buffer, sizeof(idn_buffer), 0,
+	                                stringprep_saslprep)) {
+		memset(idn_buffer, 0, sizeof(idn_buffer));
+		return NULL;
+	}
+
+	out = g_strdup(idn_buffer);
+	memset(idn_buffer, 0, sizeof(idn_buffer));
+	return out;
+#else /* USE_IDN */
+	/* TODO: Something better than disallowing all non-ASCII characters */
+	/* TODO: Is this even correct? */
+	const guchar *c;
+
+	c = (const guchar *)in;
+	while (*c) {
+		if (*c > 0x7f ||
+				(*c < 0x20 && *c != '\t' && *c != '\n' && *c != '\r'))
+			return NULL;
+	}
+
+	return g_strdup(in);
+#endif /* USE_IDN */
+}
+
 static JabberID*
 jabber_id_new_internal(const char *str, gboolean allow_terminating_slash)
 {
============================================================
--- libpurple/protocols/jabber/jutil.h	02b6b2dd78e434bf836d385baa5748633b7885d3
+++ libpurple/protocols/jabber/jutil.h	c9030d77d6bf1616a6b8476dd7788ae08e8d9279
@@ -51,6 +51,15 @@ gboolean jabber_resourceprep_validate(co
 gboolean jabber_domain_validate(const char *);
 gboolean jabber_resourceprep_validate(const char *);
 
+/**
+ * Apply the SASLprep profile of stringprep to the string passed in.
+ *
+ * @returns A newly allocated string containing the normalized version
+ *          of the input, or NULL if an error occurred (the string could
+ *          not be normalized)
+ */
+char *jabber_saslprep(const char *);
+
 PurpleConversation *jabber_find_unnormalized_conv(const char *name, PurpleAccount *account);
 
 char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len);
============================================================
--- libpurple/tests/test_jabber_scram.c	59502303261ce1097beec660446709ea04013546
+++ libpurple/tests/test_jabber_scram.c	bdb6aa6515f209808bb118bf243f91d23ab50cb9
@@ -36,7 +36,7 @@ START_TEST(test_proofs)
 /*	const char *server_signature; */
 
 	data->hash = "sha1";
-	data->password = "password";
+	data->password = g_strdup("password");
 	data->auth_message = g_string_new("n=username at jabber.org,r=8jLxB5515dhFxBil5A0xSXMH,"
 			"r=8jLxB5515dhFxBil5A0xSXMHabc,s=c2FsdA==,i=1,"
 			"c=biws,r=8jLxB5515dhFxBil5A0xSXMHabc");
@@ -48,8 +48,8 @@ START_TEST(test_proofs)
 
 	fail_unless(0 == memcmp(client_proof, data->client_proof->str, 20));
 	g_string_free(salt, TRUE);
-	g_string_free(data->auth_message, TRUE);
-	g_free(data);
+
+	jabber_scram_data_destroy(data);
 }
 END_TEST
 
@@ -61,7 +61,7 @@ START_TEST(test_mech)
 
 	data->step = 1;
 	data->hash = "sha1";
-	data->password = "password";
+	data->password = g_strdup("password");
 	data->cnonce = g_strdup("H7yDYKAWBCrM2Fa5SxGa4iez");
 	data->auth_message = g_string_new("n=paul,r=H7yDYKAWBCrM2Fa5SxGa4iez");
 


More information about the Commits mailing list