Comparison

util/sasl/scram.lua @ 3214:a69d8021b1db

Merge with Tobias.
author Waqas Hussain <waqas20@gmail.com>
date Wed, 09 Jun 2010 21:34:32 +0500
parent 3206:ff1d3f751da1
child 3374:ce52f1d5cb74
comparison
equal deleted inserted replaced
3204:7a15cbf23c5b 3214:a69d8021b1db
33 Supported Authentication Backends 33 Supported Authentication Backends
34 34
35 scram_{MECH}: 35 scram_{MECH}:
36 -- MECH being a standard hash name (like those at IANA's hash registry) with '-' replaced with '_' 36 -- MECH being a standard hash name (like those at IANA's hash registry) with '-' replaced with '_'
37 function(username, realm) 37 function(username, realm)
38 return salted_password, iteration_count, salt, state; 38 return stored_key, server_key, iteration_count, salt, state;
39 end 39 end
40 ]] 40 ]]
41 41
42 local default_i = 4096 42 local default_i = 4096
43 43
95 95
96 local function hashprep(hashname) 96 local function hashprep(hashname)
97 return hashname:lower():gsub("-", "_"); 97 return hashname:lower():gsub("-", "_");
98 end 98 end
99 99
100 function saltedPasswordSHA1(password, salt, iteration_count) 100 function getAuthenticationDatabaseSHA1(password, salt, iteration_count)
101 local salted_password
102 if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then 101 if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then
103 return false, "inappropriate argument types" 102 return false, "inappropriate argument types"
104 end 103 end
105 if iteration_count < 4096 then 104 if iteration_count < 4096 then
106 log("warn", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.") 105 log("warn", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.")
107 end 106 end
108 107 local salted_password = Hi(hmac_sha1, password, salt, iteration_count);
109 return true, Hi(hmac_sha1, password, salt, iteration_count); 108 local stored_key = sha1(hmac_sha1(salted_password, "Client Key"))
109 local server_key = hmac_sha1(salted_password, "Server Key");
110 return true, stored_key, server_key
110 end 111 end
111 112
112 local function scram_gen(hash_name, H_f, HMAC_f) 113 local function scram_gen(hash_name, H_f, HMAC_f)
113 local function scram_hash(self, message) 114 local function scram_hash(self, message)
114 if not self.state then self["state"] = {} end 115 if not self.state then self["state"] = {} end
154 155
155 self.state.salt = generate_uuid(); 156 self.state.salt = generate_uuid();
156 self.state.iteration_count = default_i; 157 self.state.iteration_count = default_i;
157 158
158 local succ = false; 159 local succ = false;
159 succ, self.state.salted_password = saltedPasswordSHA1(password, self.state.salt, default_i, self.state.iteration_count); 160 succ, self.state.stored_key, self.state.server_key = getAuthenticationDatabaseSHA1(password, self.state.salt, default_i, self.state.iteration_count);
160 if not succ then 161 if not succ then
161 log("error", "Generating salted password failed. Reason: %s", self.state.salted_password); 162 log("error", "Generating authentication database failed. Reason: %s", self.state.stored_key);
162 return "failure", "temporary-auth-failure"; 163 return "failure", "temporary-auth-failure";
163 end 164 end
164 elseif self.profile["scram_"..hashprep(hash_name)] then 165 elseif self.profile["scram_"..hashprep(hash_name)] then
165 local salted_password, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self.state.name, self.realm); 166 local stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self.state.name, self.realm);
166 if state == nil then return "failure", "not-authorized" 167 if state == nil then return "failure", "not-authorized"
167 elseif state == false then return "failure", "account-disabled" end 168 elseif state == false then return "failure", "account-disabled" end
168 169
169 self.state.salted_password = salted_password; 170 self.state.stored_key = stored_key;
171 self.state.server_key = server_key;
170 self.state.iteration_count = iteration_count; 172 self.state.iteration_count = iteration_count;
171 self.state.salt = salt 173 self.state.salt = salt
172 end 174 end
173 175
174 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count; 176 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count;
186 188
187 if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then 189 if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then
188 return "failure", "malformed-request", "Wrong nonce in client-final-message."; 190 return "failure", "malformed-request", "Wrong nonce in client-final-message.";
189 end 191 end
190 192
191 local SaltedPassword = self.state.salted_password; 193 local ServerKey = self.state.server_key;
192 local ClientKey = HMAC_f(SaltedPassword, "Client Key") 194 local StoredKey = self.state.stored_key;
193 local ServerKey = HMAC_f(SaltedPassword, "Server Key") 195
194 local StoredKey = H_f(ClientKey)
195 local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") 196 local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+")
196 local ClientSignature = HMAC_f(StoredKey, AuthMessage) 197 local ClientSignature = HMAC_f(StoredKey, AuthMessage)
197 local ClientProof = binaryXOR(ClientKey, ClientSignature) 198 local ClientKey = binaryXOR(ClientSignature, base64.decode(self.state.proof))
198 local ServerSignature = HMAC_f(ServerKey, AuthMessage) 199 local ServerSignature = HMAC_f(ServerKey, AuthMessage)
199 200
200 if base64.encode(ClientProof) == self.state.proof then 201 if StoredKey == H_f(ClientKey) then
201 local server_final_message = "v="..base64.encode(ServerSignature); 202 local server_final_message = "v="..base64.encode(ServerSignature);
202 self["username"] = self.state.name; 203 self["username"] = self.state.name;
203 return "success", server_final_message; 204 return "success", server_final_message;
204 else 205 else
205 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; 206 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated.";