From 9e9c409297871c9963d69f0302e0b791ac0c4c3e Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 8 Jun 2010 10:47:55 +0200 Subject: mod_auth_internal_hashed: Store StoredKey and ServerKey instead of salted hashed password. --- plugins/mod_auth_internal_hashed.lua | 27 +++++++++++++++------------ util/sasl/scram.lua | 11 ++++++----- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 9cffcc6e..50e0e052 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -14,7 +14,7 @@ local error = error; local ipairs = ipairs; local hashes = require "util.hashes"; local jid_bare = require "util.jid".bare; -local saltedPasswordSHA1 = require "util.sasl.scram".saltedPasswordSHA1; +local getAuthenticationDatabaseSHA1 = require "util.sasl.scram".getAuthenticationDatabaseSHA1; local config = require "core.configmanager"; local usermanager = require "core.usermanager"; local generate_uuid = require "util.uuid".generate; @@ -52,11 +52,12 @@ function new_hashpass_provider(host) if credentials.iteration_count == nil or credentials.salt == nil or string.len(credentials.salt) == 0 then return nil, "Auth failed. Stored salt and iteration count information is not complete."; end - - local valid, binpass = saltedPasswordSHA1(password, credentials.salt, credentials.iteration_count); - local hexpass = binpass:gsub(".", function (c) return ("%02x"):format(c:byte()); end); - - if valid and hexpass == credentials.hashpass then + + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); + local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); + local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); + + if valid and stored_key_hex == credentials.stored_key and server_key_hex == credentials.server_key_hex then return true; else return nil, "Auth failed. Invalid username, password, or password hash information."; @@ -102,9 +103,10 @@ function new_hashpass_provider(host) function provider.create_user(username, password) if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end local salt = generate_uuid(); - local valid, binpass = saltedPasswordSHA1(password, salt, iteration_count); - local hexpass = binpass:gsub(".", function (c) return ("%02x"):format(c:byte()); end); - return datamanager.store(username, host, "accounts", {hashpass = hexpass, salt = salt, iteration_count = iteration_count}); + local valid, stored_key, server_key = saltedPasswordSHA1(password, salt, iteration_count); + local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); + local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); + return datamanager.store(username, host, "accounts", {stored_key = stored_key_hex, server_key = server_key_hex, salt = salt, iteration_count = iteration_count}); end function provider.get_sasl_handler() @@ -124,9 +126,10 @@ function new_hashpass_provider(host) usermanager.set_password(username, credentials.password); credentials = datamanager.load(username, host, "accounts") or {}; end - local salted_password, iteration_count, salt = credentials.hashpass, credentials.iteration_count, credentials.salt; - salted_password = salted_password and salted_password:gsub("..", function(x) return string.char(tonumber(x, 16)); end); - return salted_password, iteration_count, salt, true; + local stored_key, server_key, iteration_count, salt = credentials.stored_key, credentials.server_key, credentials.iteration_count, credentials.salt; + stored_key = stored_key and stored_key:gsub("..", function(x) return string.char(tonumber(x, 16)); end); + server_key = server_key and server_key:gsub("..", function(x) return string.char(tonumber(x, 16)); end); + return stored_key, server_key, iteration_count, salt, true; end }; return new_sasl(realm, testpass_authentication_profile); diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index c366a152..08533b68 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -35,7 +35,7 @@ Supported Authentication Backends scram_{MECH}: -- MECH being a standard hash name (like those at IANA's hash registry) with '-' replaced with '_' function(username, realm) - return salted_password, iteration_count, salt, state; + return stored_key, server_key, iteration_count, salt, state; end ]] @@ -97,16 +97,17 @@ local function hashprep(hashname) return hashname:lower():gsub("-", "_"); end -function saltedPasswordSHA1(password, salt, iteration_count) - local salted_password +function getAuthenticationDatabaseSHA1(password, salt, iteration_count) if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then return false, "inappropriate argument types" end if iteration_count < 4096 then log("warn", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.") end - - return true, Hi(hmac_sha1, password, salt, iteration_count); + local salted_password = Hi(hmac_sha1, password, salt, iteration_count); + local stored_key = sha1(hmac_sha1(salted_password, "Client Key")) + local server_key = hmac_sha1(salted_password, "Server Key"); + return true, stored_key, server_key end local function scram_gen(hash_name, H_f, HMAC_f) -- cgit v1.2.3 From b31120775b59ed388bee390187d8911d8e5e4213 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 8 Jun 2010 11:00:26 +0200 Subject: util.sasl.scram: Authenticate clients by calculated StoredKey instead of ClientProof. --- util/sasl/scram.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 08533b68..63f6f2fe 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -157,17 +157,18 @@ local function scram_gen(hash_name, H_f, HMAC_f) self.state.iteration_count = default_i; local succ = false; - succ, self.state.salted_password = saltedPasswordSHA1(password, self.state.salt, default_i, self.state.iteration_count); + succ, self.state.stored_key, self.state.server_key = getAuthenticationDatabaseSHA1(password, self.state.salt, default_i, self.state.iteration_count); if not succ then - log("error", "Generating salted password failed. Reason: %s", self.state.salted_password); + log("error", "Generating authentication database failed. Reason: %s", self.state.stored_key); return "failure", "temporary-auth-failure"; end elseif self.profile["scram_"..hashprep(hash_name)] then - local salted_password, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self.state.name, self.realm); + local stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self.state.name, self.realm); if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end - self.state.salted_password = salted_password; + self.state.stored_key = stored_key; + self.state.server_key = server_key; self.state.iteration_count = iteration_count; self.state.salt = salt end @@ -189,16 +190,15 @@ local function scram_gen(hash_name, H_f, HMAC_f) return "failure", "malformed-request", "Wrong nonce in client-final-message."; end - local SaltedPassword = self.state.salted_password; - local ClientKey = HMAC_f(SaltedPassword, "Client Key") - local ServerKey = HMAC_f(SaltedPassword, "Server Key") - local StoredKey = H_f(ClientKey) + local ServerKey = self.state.server_key; + local StoredKey = self.state.stored_key; + local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") local ClientSignature = HMAC_f(StoredKey, AuthMessage) - local ClientProof = binaryXOR(ClientKey, ClientSignature) + local ClientKey = binaryXOR(ClientSignature, base64.decode(self.state.proof)) local ServerSignature = HMAC_f(ServerKey, AuthMessage) - if base64.encode(ClientProof) == self.state.proof then + if StoredKey == H_f(ClientKey) then local server_final_message = "v="..base64.encode(ServerSignature); self["username"] = self.state.name; return "success", server_final_message; -- cgit v1.2.3 From 392a5dc56c0fccbfe1a01d2cbafd95a405162b70 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 8 Jun 2010 14:54:47 +0200 Subject: mod_auth_internal_hashed: Store stored_key and server_key when setting a password. --- plugins/mod_auth_internal_hashed.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 50e0e052..c1e56ab6 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -53,6 +53,8 @@ function new_hashpass_provider(host) return nil, "Auth failed. Stored salt and iteration count information is not complete."; end + if credentials.saltedPasswordSHA1 + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); @@ -75,10 +77,13 @@ function new_hashpass_provider(host) if account.salt == nil then account.salt = generate_uuid(); end - - local valid, binpass = saltedPasswordSHA1(password, account.salt, account.iteration_count); - local hexpass = binpass:gsub(".", function (c) return ("%02x"):format(c:byte()); end); - account.hashpass = hexpass; + + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); + local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); + local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); + + account.stored_key = stored_key_hex + account.server_key = server_key_hex account.password = nil; return datamanager.store(username, host, "accounts", account); -- cgit v1.2.3 From 9cbe1a37424c67bdaf451c78ba1fe298bac9ac2b Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 8 Jun 2010 15:02:53 +0200 Subject: mod_auth_internal_hashed: Coverting salted password to stored_key and server_key. --- plugins/mod_auth_internal_hashed.lua | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index c1e56ab6..4e554584 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -22,6 +22,10 @@ local new_sasl = require "util.sasl".new; local nodeprep = require "util.encodings".stringprep.nodeprep; local hosts = hosts; +-- TODO: remove these two lines in near future +local hmac_sha1 = require "util.hmac".sha1; +local sha1 = require "util.hashes".sha1; + local prosody = _G.prosody; local is_cyrus = usermanager.is_cyrus; @@ -53,9 +57,20 @@ function new_hashpass_provider(host) return nil, "Auth failed. Stored salt and iteration count information is not complete."; end - if credentials.saltedPasswordSHA1 + local valid, stored_key, server_key + + if credentials.hexpass then + -- convert hexpass to stored_key and server_key + -- TODO: remove this in near future + valid = true; + local salted_password = credentials.hexpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); + + stored_key = sha1(hmac_sha1(salted_password, "Client Key")) + server_key = hmac_sha1(salted_password, "Server Key"); + else + valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); + end - local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); -- cgit v1.2.3 From d543622be3cad382c9f2b4febf1e8cb7f47d21d8 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Wed, 9 Jun 2010 17:51:08 +0200 Subject: mod_auth_internal_hashed: Convert hashpass to server_key/stored_key on PLAIN login. --- plugins/mod_auth_internal_hashed.lua | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 4e554584..59aef1ec 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -59,22 +59,22 @@ function new_hashpass_provider(host) local valid, stored_key, server_key - if credentials.hexpass then - -- convert hexpass to stored_key and server_key - -- TODO: remove this in near future + -- convert hexpass to stored_key and server_key + -- TODO: remove this in near future + if credentials.hashpass then valid = true; - local salted_password = credentials.hexpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); - - stored_key = sha1(hmac_sha1(salted_password, "Client Key")) - server_key = hmac_sha1(salted_password, "Server Key"); - else - valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); + local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); + log("debug", "salted_password in bin: %s", tostring(salted_password)); + credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); + credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); end + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); + local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); - if valid and stored_key_hex == credentials.stored_key and server_key_hex == credentials.server_key_hex then + if valid and stored_key_hex == credentials.stored_key and server_key_hex == credentials.server_key then return true; else return nil, "Auth failed. Invalid username, password, or password hash information."; @@ -85,15 +85,9 @@ function new_hashpass_provider(host) if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end local account = datamanager.load(username, host, "accounts"); if account then - if account.iteration_count == nil then - account.iteration_count = iteration_count; - end - - if account.salt == nil then - account.salt = generate_uuid(); - end - - local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); + account.salt = account.salt or generate_uuid(); + account.iteration_count = account.iteration_count or iteration_count; + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, account.salt, account.iteration_count); local stored_key_hex = stored_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); local server_key_hex = server_key:gsub(".", function (c) return ("%02x"):format(c:byte()); end); -- cgit v1.2.3 From 282c761001d958f0641e063026c0a3b242fd0df2 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Wed, 9 Jun 2010 17:54:34 +0200 Subject: mod_auth_internal_hashed: Convert hashpass to server_key/stored_key on SCRAM-SHA-1 login. --- plugins/mod_auth_internal_hashed.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 59aef1ec..854138e8 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -140,6 +140,15 @@ function new_hashpass_provider(host) usermanager.set_password(username, credentials.password); credentials = datamanager.load(username, host, "accounts") or {}; end + + -- convert hexpass to stored_key and server_key + -- TODO: remove this in near future + if credentials.hashpass then + local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); + credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); + credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); + end + local stored_key, server_key, iteration_count, salt = credentials.stored_key, credentials.server_key, credentials.iteration_count, credentials.salt; stored_key = stored_key and stored_key:gsub("..", function(x) return string.char(tonumber(x, 16)); end); server_key = server_key and server_key:gsub("..", function(x) return string.char(tonumber(x, 16)); end); -- cgit v1.2.3 From 480fa4dd0a6e7a3e0b5013996d01c8f0f885817a Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Wed, 9 Jun 2010 17:55:04 +0200 Subject: mod_auth_internal_hashed: Remove debugging output. --- plugins/mod_auth_internal_hashed.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 854138e8..9025ab2e 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -64,7 +64,6 @@ function new_hashpass_provider(host) if credentials.hashpass then valid = true; local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); - log("debug", "salted_password in bin: %s", tostring(salted_password)); credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); end -- cgit v1.2.3 From b0cd9c5a9a5c49c216d5131bb8eb63882c0866a9 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Wed, 9 Jun 2010 17:58:20 +0200 Subject: mod_auth_internal_hashed: Empty hashpass after conversion to stored_key/server_key and store new authentication database. --- plugins/mod_auth_internal_hashed.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 9025ab2e..4c9083aa 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -66,6 +66,8 @@ function new_hashpass_provider(host) local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); + credentials.hashpass = nil + datamanager.store(username, host, "accounts", credentials); end local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); @@ -146,6 +148,8 @@ function new_hashpass_provider(host) local salted_password = credentials.hashpass:gsub("..", function(x) return string.char(tonumber(x, 16)); end); credentials.stored_key = sha1(hmac_sha1(salted_password, "Client Key")):gsub(".", function (c) return ("%02x"):format(c:byte()); end); credentials.server_key = hmac_sha1(salted_password, "Server Key"):gsub(".", function (c) return ("%02x"):format(c:byte()); end); + credentials.hashpass = nil + datamanager.store(username, host, "accounts", credentials); end local stored_key, server_key, iteration_count, salt = credentials.stored_key, credentials.server_key, credentials.iteration_count, credentials.salt; -- cgit v1.2.3