Software /
code /
prosody
Comparison
util/sasl/scram.lua @ 2196:614c839c30c5
Completed SCRAM-SHA-1 implementation to a ready-to-test state.
author | Tobias Markmann <tm@ayena.de> |
---|---|
date | Tue, 17 Nov 2009 11:03:54 +0100 |
parent | 2194:41d42d253a1d |
child | 2197:1509cabb8321 |
comparison
equal
deleted
inserted
replaced
2195:8788c995fcbd | 2196:614c839c30c5 |
---|---|
15 | 15 |
16 local base64 = require "util.encodings".base64; | 16 local base64 = require "util.encodings".base64; |
17 local xor = require "bit".bxor | 17 local xor = require "bit".bxor |
18 local hmac_sha1 = require "util.hmac".sha1; | 18 local hmac_sha1 = require "util.hmac".sha1; |
19 local sha1 = require "util.hashes".sha1; | 19 local sha1 = require "util.hashes".sha1; |
20 local generate_uuid = require "util.uuid".generate; | |
20 | 21 |
21 module "plain" | 22 module "plain" |
22 | 23 |
23 --========================= | 24 --========================= |
24 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 | 25 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10 |
69 local function scram_sha_1(self, message) | 70 local function scram_sha_1(self, message) |
70 if not self.state then self["state"] = {} end | 71 if not self.state then self["state"] = {} end |
71 | 72 |
72 if not self.state.name then | 73 if not self.state.name then |
73 -- we are processing client_first_message | 74 -- we are processing client_first_message |
74 self.state["name"] = string.match(client_first_message, "n=(.+),r=") | 75 local client_first_message = message; |
75 self.state["clientnonce"] = string.match(client_first_message, "r=([^,]+)") | 76 self.state["name"] = client_first_message:match("n=(.+),r=") |
77 self.state["clientnonce"] = client_first_message:match("r=([^,]+)") | |
76 | 78 |
77 self.state.name = validate_username(self.state.name); | 79 self.state.name = validate_username(self.state.name); |
78 if not self.state.name then | 80 if not self.state.name or not self.state.clientnonce then |
79 return "failure", "malformed-request"; | 81 return "failure", "malformed-request"; |
80 end | 82 end |
83 self.state["servernonce"] = generate_uuid(); | |
84 self.state["salt"] = generate_uuid(); | |
85 | |
86 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i; | |
87 return "challenge", server_first_message | |
81 else | 88 else |
82 -- we are processing client_final_message | 89 -- we are processing client_final_message |
90 local client_final_message = message; | |
91 | |
92 self.state["proof"] = client_final_message:match("p=(.+)"); | |
93 self.state["nonce"] = client_final_message:match("r=(.+),p="); | |
94 self.state["channelbinding"] = client_final_message:match("c=(.+),r="); | |
95 if not self.state.proof or not self.state.nonce or not self.state.channelbinding then | |
96 return "failure", "malformed-request"; | |
97 end | |
98 | |
99 local password; | |
100 if self.profile.plain then | |
101 password, state = self.profile.plain(self.state.name, self.realm) | |
102 if state == nil then return "failure", "not-authorized" | |
103 elseif state == false then return "failure", "account-disabled" end | |
104 end | |
105 | |
106 local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i) | |
107 local ClientKey = hmac_sha1(SaltedPassword, "Client Key") | |
108 local ServerKey = hmac_sha1(SaltedPassword, "Server Key") | |
109 local StoredKey = sha1(ClientKey) | |
110 local AuthMessage = "n=" .. s_match(client_first_message,"n=(.+)") .. "," .. server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") | |
111 local ClientSignature = hmac_sha1(StoredKey, AuthMessage) | |
112 local ClientProof = binaryXOR(ClientKey, ClientSignature) | |
113 local ServerSignature = hmac_sha1(ServerKey, AuthMessage) | |
114 | |
115 if base64.encode(ClientProof) == self.state.proof then | |
116 local server_final_message = "v="..base64.encode(ServerSignature); | |
117 return "success", server_final_message; | |
118 else | |
119 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; | |
120 end | |
83 end | 121 end |
84 end | 122 end |
85 | 123 |
86 function init(registerMechanism) | 124 function init(registerMechanism) |
87 registerMechanism("SCRAM-SHA-1", {"plain"}, scram_sha_1); | 125 registerMechanism("SCRAM-SHA-1", {"plain"}, scram_sha_1); |