From fd885d08186e6a1bce88139b76cdcf7e29d72fc1 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 12 Feb 2017 10:06:30 +0300 Subject: [PATCH] Apply SASLprep before storing/converting passwords Fixes #996 and #1295 --- src/ejabberd_auth_mnesia.erl | 43 ++++++++++++++++++++++++-------- src/ejabberd_auth_riak.erl | 25 +++++++++++++------ src/ejabberd_auth_sql.erl | 48 +++++++++++++++++++++++++----------- 3 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl index 1c565d485..a4e9c1f89 100644 --- a/src/ejabberd_auth_mnesia.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -143,9 +143,12 @@ check_password(User, AuthzId, Server, Password, Digest, set_password(User, Server, Password) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), + LPassword = jid:resourceprep(Password), US = {LUser, LServer}, if (LUser == error) or (LServer == error) -> {error, invalid_jid}; + LPassword == error -> + {error, invalid_password}; true -> F = fun () -> Password2 = case is_scrammed() and is_binary(Password) @@ -167,9 +170,12 @@ try_register(User, Server, PasswordList) -> iolist_to_binary(PasswordList); true -> PasswordList end, + LPassword = jid:resourceprep(Password), US = {LUser, LServer}, if (LUser == error) or (LServer == error) -> {error, invalid_jid}; + LPassword == error -> + {error, invalid_password}; true -> F = fun () -> case mnesia:read({passwd, US}) of @@ -441,9 +447,21 @@ scram_passwords() -> ?INFO_MSG("Converting the stored passwords into " "SCRAM bits", []), - Fun = fun (#passwd{password = Password} = P) -> - Scram = password_to_scram(Password), - P#passwd{password = Scram} + Fun = fun (#passwd{us = {U, S}, password = Password} = P) + when is_binary(Password) -> + case jid:resourceprep(Password) of + error -> + ?ERROR_MSG( + "SASLprep failed for " + "password of user ~s@~s", + [U, S]), + P; + _ -> + Scram = password_to_scram(Password), + P#passwd{password = Scram} + end; + (P) -> + P end, Fields = record_info(fields, passwd), mnesia:transform_table(passwd, Fun, Fields). @@ -465,13 +483,18 @@ password_to_scram(Password, IterationCount) -> iterationcount = IterationCount}. is_password_scram_valid(Password, Scram) -> - IterationCount = Scram#scram.iterationcount, - Salt = jlib:decode_base64(Scram#scram.salt), - SaltedPassword = scram:salted_password(Password, Salt, - IterationCount), - StoredKey = - scram:stored_key(scram:client_key(SaltedPassword)), - jlib:decode_base64(Scram#scram.storedkey) == StoredKey. + case jid:resourceprep(Password) of + error -> + false; + _ -> + IterationCount = Scram#scram.iterationcount, + Salt = jlib:decode_base64(Scram#scram.salt), + SaltedPassword = scram:salted_password(Password, Salt, + IterationCount), + StoredKey = + scram:stored_key(scram:client_key(SaltedPassword)), + jlib:decode_base64(Scram#scram.storedkey) == StoredKey + end. export(_Server) -> [{passwd, diff --git a/src/ejabberd_auth_riak.erl b/src/ejabberd_auth_riak.erl index 16468dea1..67f2126be 100644 --- a/src/ejabberd_auth_riak.erl +++ b/src/ejabberd_auth_riak.erl @@ -120,9 +120,12 @@ check_password(User, AuthzId, Server, Password, Digest, set_password(User, Server, Password) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), + LPassword = jid:resourceprep(Password), US = {LUser, LServer}, if (LUser == error) or (LServer == error) -> {error, invalid_jid}; + LPassword == error -> + {error, invalid_password}; true -> Password2 = case is_scrammed() and is_binary(Password) of @@ -141,9 +144,12 @@ try_register(User, Server, PasswordList) -> iolist_to_binary(PasswordList); true -> PasswordList end, + LPassword = jid:resourceprep(Password), US = {LUser, LServer}, if (LUser == error) or (LServer == error) -> {error, invalid_jid}; + LPassword == error -> + {error, invalid_password}; true -> case ejabberd_riak:get(passwd, passwd_schema(), US) of {error, notfound} -> @@ -284,13 +290,18 @@ password_to_scram(Password, IterationCount) -> iterationcount = IterationCount}. is_password_scram_valid(Password, Scram) -> - IterationCount = Scram#scram.iterationcount, - Salt = jlib:decode_base64(Scram#scram.salt), - SaltedPassword = scram:salted_password(Password, Salt, - IterationCount), - StoredKey = - scram:stored_key(scram:client_key(SaltedPassword)), - jlib:decode_base64(Scram#scram.storedkey) == StoredKey. + case jid:resourceprep(Password) of + error -> + false; + _ -> + IterationCount = Scram#scram.iterationcount, + Salt = jlib:decode_base64(Scram#scram.salt), + SaltedPassword = scram:salted_password(Password, Salt, + IterationCount), + StoredKey = + scram:stored_key(scram:client_key(SaltedPassword)), + jlib:decode_base64(Scram#scram.storedkey) == StoredKey + end. export(_Server) -> [{passwd, diff --git a/src/ejabberd_auth_sql.erl b/src/ejabberd_auth_sql.erl index 313e9faea..4228b3345 100644 --- a/src/ejabberd_auth_sql.erl +++ b/src/ejabberd_auth_sql.erl @@ -159,10 +159,13 @@ check_password(User, AuthzId, Server, Password, Digest, set_password(User, Server, Password) -> LServer = jid:nameprep(Server), LUser = jid:nodeprep(User), + LPassword = jid:resourceprep(Password), if (LUser == error) or (LServer == error) -> {error, invalid_jid}; (LUser == <<>>) or (LServer == <<>>) -> {error, invalid_jid}; + LPassword == error -> + {error, invalid_password}; true -> case is_scrammed() of true -> @@ -193,10 +196,13 @@ set_password(User, Server, Password) -> try_register(User, Server, Password) -> LServer = jid:nameprep(Server), LUser = jid:nodeprep(User), + LPassword = jid:resourceprep(Password), if (LUser == error) or (LServer == error) -> {error, invalid_jid}; (LUser == <<>>) or (LServer == <<>>) -> {error, invalid_jid}; + LPassword == error -> + {error, invalid_password}; true -> case is_scrammed() of true -> @@ -427,13 +433,18 @@ is_password_scram_valid_stored(Password, Scram, _, _) -> is_password_scram_valid(Password, Scram). is_password_scram_valid(Password, Scram) -> - IterationCount = Scram#scram.iterationcount, - Salt = jlib:decode_base64(Scram#scram.salt), - SaltedPassword = scram:salted_password(Password, Salt, - IterationCount), - StoredKey = - scram:stored_key(scram:client_key(SaltedPassword)), - jlib:decode_base64(Scram#scram.storedkey) == StoredKey. + case jid:resourceprep(Password) of + error -> + false; + _ -> + IterationCount = Scram#scram.iterationcount, + Salt = jlib:decode_base64(Scram#scram.salt), + SaltedPassword = scram:salted_password(Password, Salt, + IterationCount), + StoredKey = + scram:stored_key(scram:client_key(SaltedPassword)), + jlib:decode_base64(Scram#scram.storedkey) == StoredKey + end. -define(BATCH_SIZE, 1000). @@ -466,14 +477,21 @@ convert_to_scram(Server) -> {selected, Rs} -> lists:foreach( fun({LUser, Password}) -> - Scram = password_to_scram(Password), - set_password_scram_t( - LUser, - Scram#scram.storedkey, - Scram#scram.serverkey, - Scram#scram.salt, - Scram#scram.iterationcount - ) + case jid:resourceprep(Password) of + error -> + ?ERROR_MSG( + "SASLprep failed for " + "password of user ~s@~s", + [LUser, LServer]); + _ -> + Scram = password_to_scram(Password), + set_password_scram_t( + LUser, + Scram#scram.storedkey, + Scram#scram.serverkey, + Scram#scram.salt, + Scram#scram.iterationcount) + end end, Rs), continue; Err -> {bad_reply, Err}