util/sasl/scram.lua
author Tobias Markmann <tm@ayena.de>
Sun, 28 Feb 2010 22:58:43 +0100
changeset 2995 175002d404b8
parent 2993 06d06fdd190b
child 2996 b0515ed4d9d7
permissions -rw-r--r--
util.sasl.scram: Adjusting authentication backend name to conform with the style already used by the plain module.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     1
-- sasl.lua v0.4
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     2
-- Copyright (C) 2008-2009 Tobias Markmann
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     3
--
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     4
--    All rights reserved.
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     5
--
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     6
--    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     7
--
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     8
--        * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
     9
--        * 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.
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    10
--        * 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.
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    11
--
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    12
--    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.
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    13
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    14
local s_match = string.match;
2198
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    15
local type = type
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    16
local string = string
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    17
local base64 = require "util.encodings".base64;
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    18
local hmac_sha1 = require "util.hmac".sha1;
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    19
local sha1 = require "util.hashes".sha1;
2196
614c839c30c5 Completed SCRAM-SHA-1 implementation to a ready-to-test state.
Tobias Markmann <tm@ayena.de>
parents: 2194
diff changeset
    20
local generate_uuid = require "util.uuid".generate;
2199
08a6b91bfe7b SASLprep usernames and passwords.
Tobias Markmann <tm@ayena.de>
parents: 2198
diff changeset
    21
local saslprep = require "util.encodings".stringprep.saslprep;
08a6b91bfe7b SASLprep usernames and passwords.
Tobias Markmann <tm@ayena.de>
parents: 2198
diff changeset
    22
local log = require "util.logger".init("sasl");
2314
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    23
local t_concat = table.concat;
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    24
local char = string.char;
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    25
local byte = string.byte;
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    26
2206
Tobias Markmann <tm@ayena.de>
parents: 2205
diff changeset
    27
module "scram"
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    28
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    29
--=========================
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    30
--SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10
2993
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    31
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    32
--[[
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    33
Supported Authentication Backends
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    34
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    35
scram-{MECH}:
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    36
	function(username, realm)
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    37
		return salted_password, iteration_count, salt, state;
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    38
	end
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    39
]]
06d06fdd190b util.sasl.scram: Adding documentation on SCRAM authentication backend.
Tobias Markmann <tm@ayena.de>
parents: 2990
diff changeset
    40
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    41
local default_i = 4096
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    42
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    43
local function bp( b )
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    44
	local result = ""
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    45
	for i=1, b:len() do
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    46
		result = result.."\\"..b:byte(i)
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    47
	end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    48
	return result
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    49
end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    50
2314
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    51
local xor_map = {0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;1;0;3;2;5;4;7;6;9;8;11;10;13;12;15;14;2;3;0;1;6;7;4;5;10;11;8;9;14;15;12;13;3;2;1;0;7;6;5;4;11;10;9;8;15;14;13;12;4;5;6;7;0;1;2;3;12;13;14;15;8;9;10;11;5;4;7;6;1;0;3;2;13;12;15;14;9;8;11;10;6;7;4;5;2;3;0;1;14;15;12;13;10;11;8;9;7;6;5;4;3;2;1;0;15;14;13;12;11;10;9;8;8;9;10;11;12;13;14;15;0;1;2;3;4;5;6;7;9;8;11;10;13;12;15;14;1;0;3;2;5;4;7;6;10;11;8;9;14;15;12;13;2;3;0;1;6;7;4;5;11;10;9;8;15;14;13;12;3;2;1;0;7;6;5;4;12;13;14;15;8;9;10;11;4;5;6;7;0;1;2;3;13;12;15;14;9;8;11;10;5;4;7;6;1;0;3;2;14;15;12;13;10;11;8;9;6;7;4;5;2;3;0;1;15;14;13;12;11;10;9;8;7;6;5;4;3;2;1;0;};
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    52
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    53
local result = {};
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    54
local function binaryXOR( a, b )
2314
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    55
	for i=1, #a do
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    56
		local x, y = byte(a, i), byte(b, i);
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    57
		local lowx, lowy = x % 16, y % 16;
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    58
		local hix, hiy = (x - lowx) / 16, (y - lowy) / 16;
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    59
		local lowr, hir = xor_map[lowx * 16 + lowy + 1], xor_map[hix * 16 + hiy + 1];
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    60
		local r = hir * 16 + lowr;
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    61
		result[i] = char(r)
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    62
	end
2314
c2e1bde4d84d Redo merge with Waqas' PBKDF2 optimizations.
Tobias Markmann <tm@ayena.de>
parents: 2290
diff changeset
    63
	return t_concat(result);
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    64
end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    65
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    66
-- hash algorithm independent Hi(PBKDF2) implementation
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    67
local function Hi(hmac, str, salt, i)
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    68
	local Ust = hmac(str, salt.."\0\0\0\1");
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    69
	local res = Ust;	
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    70
	for n=1,i-1 do
2255
92e329e1cd99 Make some more variables to locals.
Tobias Markmann <tm@ayena.de>
parents: 2210
diff changeset
    71
		local Und = hmac(str, Ust)
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    72
		res = binaryXOR(res, Und)
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    73
		Ust = Und
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    74
	end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    75
	return res
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    76
end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    77
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    78
local function validate_username(username)
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    79
	-- check for forbidden char sequences
2198
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    80
	for eq in username:gmatch("=(.?.?)") do
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    81
		if eq ~= "2D" and eq ~= "3D" then
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    82
			return false 
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    83
		end 
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    84
	end
d18b4d22b8da Making interop with libpurple. (Thanks darkrain).
Tobias Markmann <tm@ayena.de>
parents: 2197
diff changeset
    85
	
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    86
	-- replace =2D with , and =3D with =
2265
7fe644057dc2 util.sasl.scram: Making =2D and =3D substitution actually work.
Tobias Markmann <tm@ayena.de>
parents: 2255
diff changeset
    87
	username = username:gsub("=2D", ",");
7fe644057dc2 util.sasl.scram: Making =2D and =3D substitution actually work.
Tobias Markmann <tm@ayena.de>
parents: 2255
diff changeset
    88
	username = username:gsub("=3D", "=");
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    89
	
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    90
	-- apply SASLprep
2199
08a6b91bfe7b SASLprep usernames and passwords.
Tobias Markmann <tm@ayena.de>
parents: 2198
diff changeset
    91
	username = saslprep(username);
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    92
	return username;
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    93
end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    94
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
    95
local function scram_gen(hash_name, H_f, HMAC_f)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
    96
	local function scram_hash(self, message)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
    97
		if not self.state then self["state"] = {} end
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
    98
	
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
    99
		if not self.state.name then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   100
			-- we are processing client_first_message
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   101
			local client_first_message = message;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   102
			self.state["client_first_message"] = client_first_message;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   103
			self.state["name"] = client_first_message:match("n=(.+),r=")
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   104
			self.state["clientnonce"] = client_first_message:match("r=([^,]+)")
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   105
		
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   106
			if not self.state.name or not self.state.clientnonce then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   107
				return "failure", "malformed-request";
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   108
			end
2199
08a6b91bfe7b SASLprep usernames and passwords.
Tobias Markmann <tm@ayena.de>
parents: 2198
diff changeset
   109
		
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   110
			self.state.name = validate_username(self.state.name);
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   111
			if not self.state.name then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   112
				log("debug", "Username violates either SASLprep or contains forbidden character sequences.")
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   113
				return "failure", "malformed-request", "Invalid username.";
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   114
			end
2196
614c839c30c5 Completed SCRAM-SHA-1 implementation to a ready-to-test state.
Tobias Markmann <tm@ayena.de>
parents: 2194
diff changeset
   115
		
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   116
			self.state["servernonce"] = generate_uuid();
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   117
			
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   118
			-- retreive credentials
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   119
			if self.profile.plain then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   120
				password, state = self.profile.plain(self.state.name, self.realm)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   121
				if state == nil then return "failure", "not-authorized"
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   122
				elseif state == false then return "failure", "account-disabled" end
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   123
				
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   124
				password = saslprep(password);
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   125
				if not password then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   126
					log("debug", "Password violates SASLprep.");
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   127
					return "failure", "not-authorized", "Invalid password."
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   128
				end
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   129
				self.state.salt = generate_uuid();
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   130
				self.state.iteration_count = default_i;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   131
				self.state.salted_password = Hi(HMAC_f, password, self.state.salt, default_i);
2995
175002d404b8 util.sasl.scram: Adjusting authentication backend name to conform with the style already used by the plain module.
Tobias Markmann <tm@ayena.de>
parents: 2993
diff changeset
   132
			elseif self.profile["scram_"..hash_name] then
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   133
				salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm);
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   134
				if state == nil then return "failure", "not-authorized"
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   135
				elseif state == false then return "failure", "account-disabled" end
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   136
				
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   137
				self.state.salted_password = salted_password;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   138
				self.state.iteration_count = iteration_count;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   139
				self.state.salt = salt
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   140
			end
2196
614c839c30c5 Completed SCRAM-SHA-1 implementation to a ready-to-test state.
Tobias Markmann <tm@ayena.de>
parents: 2194
diff changeset
   141
		
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   142
			local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   143
			self.state["server_first_message"] = server_first_message;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   144
			return "challenge", server_first_message
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   145
		else
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   146
			if type(message) ~= "string" then return "failure", "malformed-request" end
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   147
			-- we are processing client_final_message
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   148
			local client_final_message = message;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   149
		
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   150
			self.state["proof"] = client_final_message:match("p=(.+)");
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   151
			self.state["nonce"] = client_final_message:match("r=(.+),p=");
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   152
			self.state["channelbinding"] = client_final_message:match("c=(.+),r=");
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   153
			if not self.state.proof or not self.state.nonce or not self.state.channelbinding then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   154
				return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message.";
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   155
			end
2196
614c839c30c5 Completed SCRAM-SHA-1 implementation to a ready-to-test state.
Tobias Markmann <tm@ayena.de>
parents: 2194
diff changeset
   156
		
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   157
			local SaltedPassword = self.state.salted_password;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   158
			local ClientKey = HMAC_f(SaltedPassword, "Client Key")
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   159
			local ServerKey = HMAC_f(SaltedPassword, "Server Key")
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   160
			local StoredKey = H_f(ClientKey)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   161
			local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+")
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   162
			local ClientSignature = HMAC_f(StoredKey, AuthMessage)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   163
			local ClientProof     = binaryXOR(ClientKey, ClientSignature)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   164
			local ServerSignature = HMAC_f(ServerKey, AuthMessage)
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   165
		
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   166
			if base64.encode(ClientProof) == self.state.proof then
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   167
				local server_final_message = "v="..base64.encode(ServerSignature);
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   168
				self["username"] = self.state.name;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   169
				return "success", server_final_message;
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   170
			else
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   171
				return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated.";
2199
08a6b91bfe7b SASLprep usernames and passwords.
Tobias Markmann <tm@ayena.de>
parents: 2198
diff changeset
   172
			end
2196
614c839c30c5 Completed SCRAM-SHA-1 implementation to a ready-to-test state.
Tobias Markmann <tm@ayena.de>
parents: 2194
diff changeset
   173
		end
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   174
	end
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   175
	return scram_hash;
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   176
end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   177
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   178
function init(registerMechanism)
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   179
	local function registerSCRAMMechanism(hash_name, hash, hmac_hash)
2995
175002d404b8 util.sasl.scram: Adjusting authentication backend name to conform with the style already used by the plain module.
Tobias Markmann <tm@ayena.de>
parents: 2993
diff changeset
   180
		registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash));
2990
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   181
	end
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   182
	
21933063dd9f util.sasl: Abstracting out the hash function used since SCRAM is independent of it. Adding scram-{mech} authentication backend support.
Tobias Markmann <tm@ayena.de>
parents: 2648
diff changeset
   183
	registerSCRAMMechanism("SHA-1", sha1, hmac_sha1);
2194
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   184
end
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   185
41d42d253a1d Initial commit of SCRAM SASL mechanism.
Tobias Markmann <tm@ayena.de>
parents:
diff changeset
   186
return _M;