From b4ba73c8b61d4af5282dd88216a71323c967e0e6 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
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')

diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua
index 103e8a90..43b97c55 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 cb3a0cad21e9598fb4e9ed69a4294135da755aa6 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Sun, 28 Feb 2010 22:32:12 +0100
Subject: util.sasl: Moving SASL authentication backends documentation to the
 mechanism files.

---
 util/sasl.lua            | 21 ---------------------
 util/sasl/digest-md5.lua | 15 +++++++++++++++
 util/sasl/plain.lua      | 15 +++++++++++++++
 3 files changed, 30 insertions(+), 21 deletions(-)

(limited to 'util')

diff --git a/util/sasl.lua b/util/sasl.lua
index 9c8fff78..925e5124 100644
--- a/util/sasl.lua
+++ b/util/sasl.lua
@@ -41,27 +41,6 @@ Authentication Backend Prototypes:
 state = false : disabled
 state = true : enabled
 state = nil : non-existant
-
-plain:
-	function(username, realm)
-		return password, state;
-	end
-
-plain-test:
-	function(username, realm, password)
-		return true or false, state;
-	end
-
-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 method = {};
diff --git a/util/sasl/digest-md5.lua b/util/sasl/digest-md5.lua
index 5b8f5c8a..3d6a3e1e 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 1146d48bd64689a2675364b881d59bb88e3a0323 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Sun, 28 Feb 2010 22:40:05 +0100
Subject: util.sasl.anonymous: Adding documentation on anonymous authentication
 backend.

---
 util/sasl/anonymous.lua | 10 ++++++++++
 1 file changed, 10 insertions(+)

(limited to 'util')

diff --git a/util/sasl/anonymous.lua b/util/sasl/anonymous.lua
index 65650294..d1e7d437 100644
--- a/util/sasl/anonymous.lua
+++ b/util/sasl/anonymous.lua
@@ -20,6 +20,16 @@ module "anonymous"
 
 --=========================
 --SASL ANONYMOUS according to RFC 4505
+
+--[[
+Supported Authentication Backends
+
+anonymous:
+	function(username, realm)
+		return true; --for normal usage just return true; if you don't like the supplied username you can return false.
+	end
+]]
+
 local function anonymous(self, message)
 	local username;
 	repeat
-- 
cgit v1.2.3


From ceb748bd96b32e76092518c302cb62452508cbdb Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
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')

diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua
index 43b97c55..1ceeae47 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 965aa9476a77678ed1a7c2ea58954eebd6c6bb9b Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
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')

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 263683d8c2bbb471ac3527d0bc106064c834d045 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
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 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'util')

diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua
index 1ceeae47..b813137a 100644
--- a/util/sasl/scram.lua
+++ b/util/sasl/scram.lua
@@ -129,7 +129,7 @@ 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
+			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
@@ -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 3a972b1742c28b7ef9cb5f76ed3bc69f752b5899 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Fri, 12 Mar 2010 18:37:51 +0100
Subject: util.sasl: 2009 -> 2010 in copyright header.

---
 util/sasl.lua            | 2 +-
 util/sasl/anonymous.lua  | 2 +-
 util/sasl/digest-md5.lua | 2 +-
 util/sasl/plain.lua      | 2 +-
 util/sasl/scram.lua      | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'util')

diff --git a/util/sasl.lua b/util/sasl.lua
index 925e5124..4337f47a 100644
--- a/util/sasl.lua
+++ b/util/sasl.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/anonymous.lua b/util/sasl/anonymous.lua
index d1e7d437..f3e31a7f 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 3d6a3e1e..73b310bc 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 b813137a..4875731f 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