comparison 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
comparison
equal deleted inserted replaced
28716:eb4081c68c57 28717:464d022d7d6e
179 data->client_proof->len = hash_len; 179 data->client_proof->len = hash_len;
180 data->server_signature = g_string_sized_new(hash_len); 180 data->server_signature = g_string_sized_new(hash_len);
181 data->server_signature->len = hash_len; 181 data->server_signature->len = hash_len;
182 182
183 salted_password = jabber_scram_hi(data->hash, pass, salt, iterations); 183 salted_password = jabber_scram_hi(data->hash, pass, salt, iterations);
184
185 memset(pass->str, 0, pass->allocated_len);
184 g_string_free(pass, TRUE); 186 g_string_free(pass, TRUE);
187
185 if (!salted_password) 188 if (!salted_password)
186 return FALSE; 189 return FALSE;
187 190
188 /* client_key = HMAC(salted_password, "Client Key") */ 191 /* client_key = HMAC(salted_password, "Client Key") */
189 hmac(data->hash, hash_len, client_key, salted_password, "Client Key"); 192 hmac(data->hash, hash_len, client_key, salted_password, "Client Key");
354 purple_debug_error("jabber", "SCRAM: There is no step %d\n", data->step); 357 purple_debug_error("jabber", "SCRAM: There is no step %d\n", data->step);
355 return FALSE; 358 return FALSE;
356 } 359 }
357 360
358 return TRUE; 361 return TRUE;
362 }
363
364 static gchar *escape_username(const gchar *in)
365 {
366 GString *s = g_string_new(in);
367 gchar *c;
368 gsize i = 0;
369
370 c = s->str;
371 while (*c) {
372 if (*c == ',' || *c == '=') {
373 g_string_erase(s, i, 1);
374 g_string_insert(s, i, *c == ',' ? "=2C" : "=3D");
375 }
376
377 ++c; ++i;
378 }
379
380 return g_string_free(s, FALSE);
359 } 381 }
360 382
361 static xmlnode *scram_start(JabberStream *js, xmlnode *mechanisms) 383 static xmlnode *scram_start(JabberStream *js, xmlnode *mechanisms)
362 { 384 {
363 xmlnode *reply; 385 xmlnode *reply;
365 guint64 cnonce; 387 guint64 cnonce;
366 #ifdef CHANNEL_BINDING 388 #ifdef CHANNEL_BINDING
367 gboolean binding_supported = TRUE; 389 gboolean binding_supported = TRUE;
368 #endif 390 #endif
369 gchar *dec_out, *enc_out; 391 gchar *dec_out, *enc_out;
392 gchar *prepped_node, *tmp;
393 gchar *prepped_pass;
394
395 prepped_node = jabber_saslprep(js->user->node);
396 if (!prepped_node) {
397 /* TODO: Error handling in the response value from scram_start */
398 return NULL;
399 }
400
401 tmp = escape_username(prepped_node);
402 g_free(prepped_node);
403 prepped_node = tmp;
404
405 prepped_pass = jabber_saslprep(purple_connection_get_password(js->gc));
406 if (!prepped_pass) {
407 g_free(prepped_node);
408 return NULL;
409 }
370 410
371 data = js->auth_mech_data = g_new0(JabberScramData, 1); 411 data = js->auth_mech_data = g_new0(JabberScramData, 1);
372 data->hash = mech_to_hash(js->auth_mech->name); 412 data->hash = mech_to_hash(js->auth_mech->name);
373 data->password = purple_connection_get_password(js->gc); 413 data->password = prepped_pass;
374 414
375 #ifdef CHANNEL_BINDING 415 #ifdef CHANNEL_BINDING
376 if (strstr(js->auth_mech_name, "-PLUS")) 416 if (strstr(js->auth_mech_name, "-PLUS"))
377 data->channel_binding = TRUE; 417 data->channel_binding = TRUE;
378 #endif 418 #endif
379 cnonce = ((guint64)g_random_int() << 32) | g_random_int(); 419 cnonce = ((guint64)g_random_int() << 32) | g_random_int();
380 data->cnonce = purple_base64_encode((guchar *)&cnonce, sizeof(cnonce)); 420 data->cnonce = purple_base64_encode((guchar *)&cnonce, sizeof(cnonce));
381 421
382 data->auth_message = g_string_new(NULL); 422 data->auth_message = g_string_new(NULL);
383 g_string_printf(data->auth_message, "n=%s,r=%s", 423 g_string_printf(data->auth_message, "n=%s,r=%s",
384 js->user->node /* TODO: SaslPrep */, 424 prepped_node, data->cnonce);
385 data->cnonce); 425 g_free(prepped_node);
386 426
387 data->step = 1; 427 data->step = 1;
388 428
389 reply = xmlnode_new("auth"); 429 reply = xmlnode_new("auth");
390 xmlnode_set_namespace(reply, NS_XMPP_SASL); 430 xmlnode_set_namespace(reply, NS_XMPP_SASL);
498 g_string_free(data->auth_message, TRUE); 538 g_string_free(data->auth_message, TRUE);
499 if (data->client_proof) 539 if (data->client_proof)
500 g_string_free(data->client_proof, TRUE); 540 g_string_free(data->client_proof, TRUE);
501 if (data->server_signature) 541 if (data->server_signature)
502 g_string_free(data->server_signature, TRUE); 542 g_string_free(data->server_signature, TRUE);
543 if (data->password) {
544 memset(data->password, 0, strlen(data->password));
545 g_free(data->password);
546 }
547
503 g_free(data); 548 g_free(data);
504 } 549 }
505 550
506 static void scram_dispose(JabberStream *js) 551 static void scram_dispose(JabberStream *js)
507 { 552 {