From 03e17022ef1117321cd3898e7282f396692d824a Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 28 Feb 2010 22:32:12 +0100 Subject: util.sasl: Moving SASL authentication backends documentation to the mechanism files. --- util/sasl/digest-md5.lua | 15 +++++++++++++++ util/sasl/plain.lua | 15 +++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'util/sasl') diff --git a/util/sasl/digest-md5.lua b/util/sasl/digest-md5.lua index 04acf04d..fc2107bc 100644 --- a/util/sasl/digest-md5.lua +++ b/util/sasl/digest-md5.lua @@ -29,6 +29,21 @@ module "digest-md5" --========================= --SASL DIGEST-MD5 according to RFC 2831 +--[[ +Supported Authentication Backends + +digest-md5: + function(username, domain, realm, encoding) -- domain and realm are usually the same; for some broken + -- implementations it's not + return digesthash, state; + end + +digest-md5-test: + function(username, domain, realm, encoding, digesthash) + return true or false, state; + end +]] + local function digest(self, message) --TODO complete support for authzid diff --git a/util/sasl/plain.lua b/util/sasl/plain.lua index ae5c777a..43bb239f 100644 --- a/util/sasl/plain.lua +++ b/util/sasl/plain.lua @@ -19,6 +19,21 @@ module "plain" -- ================================ -- SASL PLAIN according to RFC 4616 + +--[[ +Supported Authentication Backends + +plain: + function(username, realm) + return password, state; + end + +plain-test: + function(username, realm, password) + return true or false, state; + end +]] + local function plain(self, message) if not message then return "failure", "malformed-request"; -- cgit v1.2.3 From 866437fa873a62c35bc84aad821343cd9fbf377e Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 28 Feb 2010 22:50:25 +0100 Subject: util.sasl.plain: Adding plain_hashed authentication backend support. --- util/sasl/plain.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'util/sasl') diff --git a/util/sasl/plain.lua b/util/sasl/plain.lua index 43bb239f..6369face 100644 --- a/util/sasl/plain.lua +++ b/util/sasl/plain.lua @@ -32,6 +32,11 @@ plain-test: function(username, realm, password) return true or false, state; end + +plain-hashed: + function(username, realm) + return hashed_password, hash_function, state; + end ]] local function plain(self, message) @@ -61,6 +66,10 @@ local function plain(self, message) if correct_password == password then correct = true; else correct = false; end elseif self.profile.plain_test then correct, state = self.profile.plain_test(authentication, self.realm, password); + elseif self.profile.plain_hashed then + local hashed_password, hash_f; + hashed_password, hash_f, state = self.profile.plain_hashed(authentication, self.realm); + if hashed_password == hash_f(password) then correct = true; else correct = false; end end self.username = authentication @@ -76,7 +85,7 @@ local function plain(self, message) end function init(registerMechanism) - registerMechanism("PLAIN", {"plain", "plain_test"}, plain); + registerMechanism("PLAIN", {"plain", "plain_test", "plain_hashed"}, plain); end return _M; -- cgit v1.2.3 From ddc193c83165e2f37c21889aeaf22c7a3cd9deab Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Fri, 12 Mar 2010 18:37:51 +0100 Subject: util.sasl: 2009 -> 2010 in copyright header. --- util/sasl/anonymous.lua | 2 +- util/sasl/digest-md5.lua | 2 +- util/sasl/plain.lua | 2 +- util/sasl/scram.lua | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/anonymous.lua b/util/sasl/anonymous.lua index 65650294..7b5a5081 100644 --- a/util/sasl/anonymous.lua +++ b/util/sasl/anonymous.lua @@ -1,5 +1,5 @@ -- sasl.lua v0.4 --- Copyright (C) 2008-2009 Tobias Markmann +-- Copyright (C) 2008-2010 Tobias Markmann -- -- All rights reserved. -- diff --git a/util/sasl/digest-md5.lua b/util/sasl/digest-md5.lua index fc2107bc..8986ca45 100644 --- a/util/sasl/digest-md5.lua +++ b/util/sasl/digest-md5.lua @@ -1,5 +1,5 @@ -- sasl.lua v0.4 --- Copyright (C) 2008-2009 Tobias Markmann +-- Copyright (C) 2008-2010 Tobias Markmann -- -- All rights reserved. -- diff --git a/util/sasl/plain.lua b/util/sasl/plain.lua index 6369face..2abbc53a 100644 --- a/util/sasl/plain.lua +++ b/util/sasl/plain.lua @@ -1,5 +1,5 @@ -- sasl.lua v0.4 --- Copyright (C) 2008-2009 Tobias Markmann +-- Copyright (C) 2008-2010 Tobias Markmann -- -- All rights reserved. -- diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 103e8a90..19fb7a18 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -1,5 +1,5 @@ -- sasl.lua v0.4 --- Copyright (C) 2008-2009 Tobias Markmann +-- Copyright (C) 2008-2010 Tobias Markmann -- -- All rights reserved. -- -- cgit v1.2.3 From e169b45da9cfc3a6d19cfedc2cb7d18248b6a019 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Fri, 21 May 2010 23:40:29 +0200 Subject: util.sasl.plain: Removing plain_hashed authentication provider. Just do hashing and comparison yourself in a plain_test authentication provider. --- util/sasl/plain.lua | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/plain.lua b/util/sasl/plain.lua index 2abbc53a..f1e04f32 100644 --- a/util/sasl/plain.lua +++ b/util/sasl/plain.lua @@ -32,11 +32,6 @@ plain-test: function(username, realm, password) return true or false, state; end - -plain-hashed: - function(username, realm) - return hashed_password, hash_function, state; - end ]] local function plain(self, message) @@ -66,10 +61,6 @@ local function plain(self, message) if correct_password == password then correct = true; else correct = false; end elseif self.profile.plain_test then correct, state = self.profile.plain_test(authentication, self.realm, password); - elseif self.profile.plain_hashed then - local hashed_password, hash_f; - hashed_password, hash_f, state = self.profile.plain_hashed(authentication, self.realm); - if hashed_password == hash_f(password) then correct = true; else correct = false; end end self.username = authentication @@ -85,7 +76,7 @@ local function plain(self, message) end function init(registerMechanism) - registerMechanism("PLAIN", {"plain", "plain_test", "plain_hashed"}, plain); + registerMechanism("PLAIN", {"plain", "plain_test"}, plain); end return _M; -- cgit v1.2.3 From eb398e4d08506202d9a67fed60c355afd70c0f81 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 28 Feb 2010 22:23:03 +0100 Subject: util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support. --- util/sasl/scram.lua | 132 +++++++++++++++++++++++++++++----------------------- 1 file changed, 75 insertions(+), 57 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 19fb7a18..4e52f5cd 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -82,77 +82,95 @@ local function validate_username(username) return username; end -local function scram_sha_1(self, message) - if not self.state then self["state"] = {} end +local function scram_gen(hash_name, H_f, HMAC_f) + local function scram_hash(self, message) + if not self.state then self["state"] = {} end - if not self.state.name then - -- we are processing client_first_message - local client_first_message = message; - self.state["client_first_message"] = client_first_message; - self.state["name"] = client_first_message:match("n=(.+),r=") - self.state["clientnonce"] = client_first_message:match("r=([^,]+)") - - if not self.state.name or not self.state.clientnonce then - return "failure", "malformed-request"; - end - - self.state.name = validate_username(self.state.name); if not self.state.name then - log("debug", "Username violates either SASLprep or contains forbidden character sequences.") - return "failure", "malformed-request", "Invalid username."; - end + -- we are processing client_first_message + local client_first_message = message; + self.state["client_first_message"] = client_first_message; + self.state["name"] = client_first_message:match("n=(.+),r=") + self.state["clientnonce"] = client_first_message:match("r=([^,]+)") - self.state["servernonce"] = generate_uuid(); - self.state["salt"] = generate_uuid(); + if not self.state.name or not self.state.clientnonce then + return "failure", "malformed-request"; + end - local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i; - self.state["server_first_message"] = server_first_message; - return "challenge", server_first_message - else - if type(message) ~= "string" then return "failure", "malformed-request" end - -- we are processing client_final_message - local client_final_message = message; + self.state.name = validate_username(self.state.name); + if not self.state.name then + log("debug", "Username violates either SASLprep or contains forbidden character sequences.") + return "failure", "malformed-request", "Invalid username."; + end - self.state["proof"] = client_final_message:match("p=(.+)"); - self.state["nonce"] = client_final_message:match("r=(.+),p="); - self.state["channelbinding"] = client_final_message:match("c=(.+),r="); - if not self.state.proof or not self.state.nonce or not self.state.channelbinding then - return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; - end + self.state["servernonce"] = generate_uuid(); + + -- retreive credentials + if self.profile.plain then + password, state = self.profile.plain(self.state.name, self.realm) + if state == nil then return "failure", "not-authorized" + elseif state == false then return "failure", "account-disabled" end + + password = saslprep(password); + if not password then + log("debug", "Password violates SASLprep."); + return "failure", "not-authorized", "Invalid password." + end + self.state.salt = generate_uuid(); + self.state.iteration_count = default_i; + self.state.salted_password = Hi(HMAC_f, password, self.state.salt, default_i); + elseif self.profile["scram-"..hash_name] then + salted_password, iteration_count, salt, state = self.profile["scram-"..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.iteration_count = iteration_count; + self.state.salt = salt + end - local password, state; - if self.profile.plain then - password, state = self.profile.plain(self.state.name, self.realm) - if state == nil then return "failure", "not-authorized" - elseif state == false then return "failure", "account-disabled" end - password = saslprep(password); - if not password then - log("debug", "Password violates SASLprep."); - return "failure", "not-authorized", "Invalid password." + local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count; + self.state["server_first_message"] = server_first_message; + return "challenge", server_first_message + else + if type(message) ~= "string" then return "failure", "malformed-request" end + -- we are processing client_final_message + local client_final_message = message; + + self.state["proof"] = client_final_message:match("p=(.+)"); + self.state["nonce"] = client_final_message:match("r=(.+),p="); + self.state["channelbinding"] = client_final_message:match("c=(.+),r="); + if not self.state.proof or not self.state.nonce or not self.state.channelbinding then + return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; end - end - local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i) - local ClientKey = hmac_sha1(SaltedPassword, "Client Key") - local ServerKey = hmac_sha1(SaltedPassword, "Server Key") - local StoredKey = sha1(ClientKey) - 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_sha1(StoredKey, AuthMessage) - local ClientProof = binaryXOR(ClientKey, ClientSignature) - local ServerSignature = hmac_sha1(ServerKey, AuthMessage) + 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 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 ServerSignature = HMAC_f(ServerKey, AuthMessage) - if base64.encode(ClientProof) == self.state.proof then - local server_final_message = "v="..base64.encode(ServerSignature); - self["username"] = self.state.name; - return "success", server_final_message; - else - return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; + if base64.encode(ClientProof) == self.state.proof then + local server_final_message = "v="..base64.encode(ServerSignature); + self["username"] = self.state.name; + return "success", server_final_message; + else + return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; + end end end + return scram_hash; end function init(registerMechanism) - registerMechanism("SCRAM-SHA-1", {"plain"}, scram_sha_1); + local function registerSCRAMMechanism(hash_name, hash, hmac_hash) + registerMechanism("SCRAM-"..hash_name, {"plain", "scram-"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash)); + end + + registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); end return _M; \ No newline at end of file -- cgit v1.2.3 From 1d5c54a2f55c1e60313c6aa4cc411edd7c7578c5 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 28 Feb 2010 22:42:53 +0100 Subject: util.sasl.scram: Adding documentation on SCRAM authentication backend. --- util/sasl/scram.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 4e52f5cd..14fb8beb 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -28,6 +28,16 @@ module "scram" --========================= --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 + +--[[ +Supported Authentication Backends + +scram-{MECH}: + function(username, realm) + return salted_password, iteration_count, salt, state; + end +]] + local default_i = 4096 local function bp( b ) -- cgit v1.2.3 From e1b9d33130e9eda7c9dc656880f2aaf25f7b22cc Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 6 May 2010 15:19:20 +0500 Subject: util.sasl.scram: Fixed global access. --- util/sasl/scram.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 14fb8beb..ed7d7bc3 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -117,7 +117,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- retreive credentials if self.profile.plain then - password, state = self.profile.plain(self.state.name, self.realm) + local password, state = self.profile.plain(self.state.name, self.realm) if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end @@ -129,8 +129,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) self.state.salt = generate_uuid(); self.state.iteration_count = default_i; self.state.salted_password = Hi(HMAC_f, password, self.state.salt, default_i); - elseif self.profile["scram-"..hash_name] then - salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm); + elseif self.profile["scram_"..hash_name] then + local salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm); if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end @@ -177,7 +177,7 @@ end function init(registerMechanism) local function registerSCRAMMechanism(hash_name, hash, hmac_hash) - registerMechanism("SCRAM-"..hash_name, {"plain", "scram-"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash)); + registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash)); end registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); -- cgit v1.2.3 From b7a87c093211d21bb626c13505d8c6b5575e4bd2 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 01:48:31 +0200 Subject: util.sasl.scram: Check nonce in client final message. Check channel binding flag in client first message. Adding some TODOs on more strict parsing. (thanks Marc Santamaria) --- util/sasl/scram.lua | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index ed7d7bc3..ffca171c 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -1,15 +1,15 @@ -- sasl.lua v0.4 -- Copyright (C) 2008-2010 Tobias Markmann -- --- All rights reserved. +-- All rights reserved. -- --- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- --- * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. --- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. --- * Neither the name of Tobias Markmann nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +-- * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +-- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +-- * Neither the name of Tobias Markmann nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. local s_match = string.match; local type = type @@ -99,13 +99,21 @@ local function scram_gen(hash_name, H_f, HMAC_f) if not self.state.name then -- we are processing client_first_message local client_first_message = message; + + -- TODO: more strict parsing of client_first_message + -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; self.state["name"] = client_first_message:match("n=(.+),r=") self.state["clientnonce"] = client_first_message:match("r=([^,]+)") - - if not self.state.name or not self.state.clientnonce then + self.state["gs2_cbind_flag"] = client_first_message:sub(1, 1) + -- we don't do any channel binding yet + if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then return "failure", "malformed-request"; end + + if not self.state.name or not self.state.clientnonce then + return "failure", "malformed-request", "Channel binding isn't support at this time."; + end self.state.name = validate_username(self.state.name); if not self.state.name then @@ -146,14 +154,20 @@ local function scram_gen(hash_name, H_f, HMAC_f) if type(message) ~= "string" then return "failure", "malformed-request" end -- we are processing client_final_message local client_final_message = message; - + + -- TODO: more strict parsing of client_final_message self.state["proof"] = client_final_message:match("p=(.+)"); self.state["nonce"] = client_final_message:match("r=(.+),p="); self.state["channelbinding"] = client_final_message:match("c=(.+),r="); + if not self.state.proof or not self.state.nonce or not self.state.channelbinding then return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; end - + + if self.state.nonce ~= self.state.servernonce then + return "failure", "malformed-request", "Wrong nonce in client-second-message."; + end + local SaltedPassword = self.state.salted_password; local ClientKey = HMAC_f(SaltedPassword, "Client Key") local ServerKey = HMAC_f(SaltedPassword, "Server Key") @@ -162,7 +176,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) local ClientSignature = HMAC_f(StoredKey, AuthMessage) local ClientProof = binaryXOR(ClientKey, ClientSignature) local ServerSignature = HMAC_f(ServerKey, AuthMessage) - + if base64.encode(ClientProof) == self.state.proof then local server_final_message = "v="..base64.encode(ServerSignature); self["username"] = self.state.name; @@ -179,7 +193,7 @@ function init(registerMechanism) local function registerSCRAMMechanism(hash_name, hash, hmac_hash) registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash)); end - + registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); end -- cgit v1.2.3 From a69a0446406c8b2b76aefce317e1c1820e55e4f8 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 13:58:15 +0200 Subject: util.sasl.scram: Parsing client-first-message in a more strict way. (thanks Marc Santamaria) --- util/sasl/scram.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index ffca171c..4c5df11a 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -100,12 +100,10 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- we are processing client_first_message local client_first_message = message; - -- TODO: more strict parsing of client_first_message -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; - self.state["name"] = client_first_message:match("n=(.+),r=") - self.state["clientnonce"] = client_first_message:match("r=([^,]+)") - self.state["gs2_cbind_flag"] = client_first_message:sub(1, 1) + self.state["gs2_cbind_flag"], self.state["authzid"], self.state["name"], self.state["clientnonce"] = client_first_message:match("^(%a),(.*),n=(.*),r=([^,]*).*"); + -- we don't do any channel binding yet if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then return "failure", "malformed-request"; -- cgit v1.2.3 From 1f64550d6c9be4511288bb72d2ebc88223918dd6 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 13:59:58 +0200 Subject: util.sasl.scram: Fix in nonce check of client-final-message. --- util/sasl/scram.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 4c5df11a..7b9123ee 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -162,8 +162,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; end - if self.state.nonce ~= self.state.servernonce then - return "failure", "malformed-request", "Wrong nonce in client-second-message."; + if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then + return "failure", "malformed-request", "Wrong nonce in client-final-message."; end local SaltedPassword = self.state.salted_password; -- cgit v1.2.3 From 621f91d4a67b07ad89853e2197fc9a62302a75fd Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 14:47:21 +0200 Subject: util.sasl.scram: Parsing client-final-message in a more strict way. (thanks Marc Santamaria) --- util/sasl/scram.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 7b9123ee..0188d5cf 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -153,10 +153,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- we are processing client_final_message local client_final_message = message; - -- TODO: more strict parsing of client_final_message - self.state["proof"] = client_final_message:match("p=(.+)"); - self.state["nonce"] = client_final_message:match("r=(.+),p="); - self.state["channelbinding"] = client_final_message:match("c=(.+),r="); + self.state["channelbinding"], self.state["nonce"], self.state["proof"] = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); if not self.state.proof or not self.state.nonce or not self.state.channelbinding then return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; -- cgit v1.2.3 From 47c7c633170ae0d947a7f22e720f1868fec63332 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 14:58:24 +0200 Subject: util.sasl.scram: Split up long line. --- util/sasl/scram.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 0188d5cf..13b9932f 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -102,7 +102,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; - self.state["gs2_cbind_flag"], self.state["authzid"], self.state["name"], self.state["clientnonce"] = client_first_message:match("^(%a),(.*),n=(.*),r=([^,]*).*"); + self.state["gs2_cbind_flag"], self.state["authzid"], self.state["name"], self.state["clientnonce"] + = client_first_message:match("^(%a),(.*),n=(.*),r=([^,]*).*"); -- we don't do any channel binding yet if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then -- cgit v1.2.3 From 229d07afa05408750fbc8314bd4e51243b9daf4d Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 19:04:53 +0200 Subject: util.sasl.scram: Providing an API function to generate a salted password for the SCRAM-SHA-1 mechanism. --- util/sasl/scram.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 13b9932f..39daf397 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -92,6 +92,18 @@ local function validate_username(username) return username; end +function saltedPasswordSHA1(password, salt, iteration_count) + local salted_password + if type(password) ~= "string" and type(salt) ~= "string" and type(iteration_count) ~= "number" then + return false, "inappropriate argument types" + end + if iteration_count < 4096 then + log("warning", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.") + end + + return true, Hi(hmac_sha1, password, salt, iteration_count); +end + local function scram_gen(hash_name, H_f, HMAC_f) local function scram_hash(self, message) if not self.state then self["state"] = {} end @@ -133,9 +145,16 @@ local function scram_gen(hash_name, H_f, HMAC_f) log("debug", "Password violates SASLprep."); return "failure", "not-authorized", "Invalid password." end + self.state.salt = generate_uuid(); self.state.iteration_count = default_i; - self.state.salted_password = Hi(HMAC_f, password, self.state.salt, default_i); + + local succ = false; + succ, self.state.salted_password = saltedPasswordSHA1(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); + return "failure", "temporary-auth-failure"; + end elseif self.profile["scram_"..hash_name] then local salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm); if state == nil then return "failure", "not-authorized" -- cgit v1.2.3 From 44b60251257f7ca176c3436dad3220137a1eb5b7 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 20:34:32 +0200 Subject: util.sasl.plain: Typo. --- util/sasl/plain.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util/sasl') diff --git a/util/sasl/plain.lua b/util/sasl/plain.lua index f1e04f32..39821182 100644 --- a/util/sasl/plain.lua +++ b/util/sasl/plain.lua @@ -28,7 +28,7 @@ plain: return password, state; end -plain-test: +plain_test: function(username, realm, password) return true or false, state; end -- cgit v1.2.3 From 7847a8a20fc9fc0b057bf7f99fd0d0a80b4d85e3 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 22 May 2010 20:51:01 +0200 Subject: util.sasl.scram: Fixing issue #177. --- util/sasl/scram.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 39daf397..47e8e7b3 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -108,6 +108,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) local function scram_hash(self, message) if not self.state then self["state"] = {} end + if type(message) ~= "string" or #message == 0 then return "failure", "malformed-request" end if not self.state.name then -- we are processing client_first_message local client_first_message = message; @@ -169,7 +170,6 @@ local function scram_gen(hash_name, H_f, HMAC_f) self.state["server_first_message"] = server_first_message; return "challenge", server_first_message else - if type(message) ~= "string" then return "failure", "malformed-request" end -- we are processing client_final_message local client_final_message = message; -- cgit v1.2.3 From 4b31a9798fee915ced267f8196af658d74075652 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 28 Feb 2010 22:58:43 +0100 Subject: util.sasl.scram: Adjusting authentication backend name to conform with the style already used by the plain module. --- util/sasl/scram.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util/sasl') diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 47e8e7b3..6040c402 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -212,4 +212,4 @@ function init(registerMechanism) registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); end -return _M; \ No newline at end of file +return _M; -- cgit v1.2.3