Diff

util/sasl/scram.lua @ 5843:fb6573e191cf

Merge Tobias SCRAM-PLUS work
author Kim Alvefur <zash@zash.se>
date Sun, 22 Sep 2013 00:44:20 +0200
parent 5776:bd0ff8ae98a8
parent 5841:1b0c7e7c6be8
child 5844:4f545674b0bc
line wrap: on
line diff
--- a/util/sasl/scram.lua	Mon Sep 16 18:41:30 2013 +0100
+++ b/util/sasl/scram.lua	Sun Sep 22 00:44:20 2013 +0200
@@ -14,6 +14,7 @@
 local s_match = string.match;
 local type = type
 local string = string
+local tostring = tostring;
 local base64 = require "util.encodings".base64;
 local hmac_sha1 = require "util.hashes".hmac_sha1;
 local sha1 = require "util.hashes".sha1;
@@ -39,6 +40,10 @@
 	function(username, realm)
 		return stored_key, server_key, iteration_count, salt, state;
 	end
+
+Supported Channel Binding Backends
+
+'tls-unique' according to RFC 5929
 ]]
 
 local default_i = 4096
@@ -108,6 +113,8 @@
 local function scram_gen(hash_name, H_f, HMAC_f)
 	local function scram_hash(self, message)
 		if not self.state then self["state"] = {} end
+		local support_channel_binding = false;
+		if self.profile.cb then support_channel_binding = true; end
 
 		if type(message) ~= "string" or #message == 0 then return "failure", "malformed-request" end
 		if not self.state.name then
@@ -116,12 +123,29 @@
 
 			-- 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["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"]
+				= client_first_message:match("^(%a)=?([%a%-]*),(.*),n=(.*),r=([^,]*).*");
+
+			-- check for invalid gs2_flag_type start
+			local gs2_flag_type = string.sub(self.state.gs2_cbind_flag, 0, 1)
+			if gs2_flag_type ~=  "y" and gs2_flag_type ~=  "n" and gs2_flag_type ~=  "p" then
+				return "failure", "malformed-request", "The GS2 header has to start with 'y', 'n', or 'p'."
+			end
 
-			-- 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";
+			if support_channel_binding then
+				if string.sub(self.state.gs2_cbind_flag, 0, 1) == "y" then
+					return "failure", "malformed-request";
+				end
+				
+				-- check whether we support the proposed channel binding type
+				if not self.profile.cb[self.state.gs2_cbind_name] then
+					return "failure", "malformed-request", "Proposed channel binding type isn't supported.";
+				end
+			else
+				-- we don't support channelbinding, 
+				if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then
+					return "failure", "malformed-request";
+				end
 			end
 
 			if not self.state.name or not self.state.clientnonce then
@@ -181,6 +205,16 @@
 				return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message.";
 			end
 
+			if self.state.gs2_cbind_name then
+				-- we support channelbinding, so check if the value is valid
+				local client_gs2_header = base64.decode(self.state.channelbinding)
+				local our_client_gs2_header = "p="..self.state.gs2_cbind_name..","..self.state["authzid"]..","..self.profile.cb[self.state.gs2_cbind_name](self);
+
+				if client_gs2_header ~= our_client_gs2_header then
+					return "failure", "malformed-request", "Invalid channel binding value.";
+				end
+			end
+
 			if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then
 				return "failure", "malformed-request", "Wrong nonce in client-final-message.";
 			end
@@ -208,6 +242,9 @@
 function init(registerMechanism)
 	local function registerSCRAMMechanism(hash_name, hash, hmac_hash)
 		registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash));
+		
+		-- register channel binding equivalent
+		registerMechanism("SCRAM-"..hash_name.."-PLUS", {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash), {"tls-unique"});
 	end
 
 	registerSCRAMMechanism("SHA-1", sha1, hmac_sha1);