Mercurial > pidgin
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 { |