Software /
code /
prosody
Comparison
util/sasl/scram.lua @ 2198:d18b4d22b8da
Making interop with libpurple. (Thanks darkrain).
author | Tobias Markmann <tm@ayena.de> |
---|---|
date | Tue, 17 Nov 2009 22:39:18 +0100 |
parent | 2197:1509cabb8321 |
child | 2199:08a6b91bfe7b |
comparison
equal
deleted
inserted
replaced
2197:1509cabb8321 | 2198:d18b4d22b8da |
---|---|
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. | 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. |
11 -- | 11 -- |
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. | 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. |
13 | 13 |
14 local s_match = string.match; | 14 local s_match = string.match; |
15 | 15 local type = type |
16 local string = string | |
16 local base64 = require "util.encodings".base64; | 17 local base64 = require "util.encodings".base64; |
17 local xor = require "bit".bxor | 18 local xor = require "bit".bxor |
18 local hmac_sha1 = require "util.hmac".sha1; | 19 local hmac_sha1 = require "util.hmac".sha1; |
19 local sha1 = require "util.hashes".sha1; | 20 local sha1 = require "util.hashes".sha1; |
20 local generate_uuid = require "util.uuid".generate; | 21 local generate_uuid = require "util.uuid".generate; |
32 end | 33 end |
33 return result | 34 return result |
34 end | 35 end |
35 | 36 |
36 local function binaryXOR( a, b ) | 37 local function binaryXOR( a, b ) |
37 if string.len(a) > string.len(b) then | 38 if a:len() > b:len() then |
38 b = string.rep("\0", a:len() - b:len())..b | 39 b = string.rep("\0", a:len() - b:len())..b |
39 elseif string.len(a) < string.len(b) then | 40 elseif string.len(a) < string.len(b) then |
40 a = string.rep("\0", b:len() - a:len())..a | 41 a = string.rep("\0", b:len() - a:len())..a |
41 end | 42 end |
42 local result = "" | 43 local result = "" |
58 return res | 59 return res |
59 end | 60 end |
60 | 61 |
61 local function validate_username(username) | 62 local function validate_username(username) |
62 -- check for forbidden char sequences | 63 -- check for forbidden char sequences |
63 for eq in s:gmatch("=(.?.?)") do | 64 for eq in username:gmatch("=(.?.?)") do |
64 if eq ~= "2D" and eq ~= "3D" then return false end end return true; | 65 if eq ~= "2D" and eq ~= "3D" then |
66 return false | |
67 end | |
68 end | |
69 | |
65 -- replace =2D with , and =3D with = | 70 -- replace =2D with , and =3D with = |
66 | 71 |
67 -- apply SASLprep | 72 -- apply SASLprep |
68 return username; | 73 return username; |
69 end | 74 end |
72 if not self.state then self["state"] = {} end | 77 if not self.state then self["state"] = {} end |
73 | 78 |
74 if not self.state.name then | 79 if not self.state.name then |
75 -- we are processing client_first_message | 80 -- we are processing client_first_message |
76 local client_first_message = message; | 81 local client_first_message = message; |
82 self.state["client_first_message"] = client_first_message; | |
77 self.state["name"] = client_first_message:match("n=(.+),r=") | 83 self.state["name"] = client_first_message:match("n=(.+),r=") |
78 self.state["clientnonce"] = client_first_message:match("r=([^,]+)") | 84 self.state["clientnonce"] = client_first_message:match("r=([^,]+)") |
79 | 85 |
80 self.state.name = validate_username(self.state.name); | 86 self.state.name = validate_username(self.state.name); |
81 if not self.state.name or not self.state.clientnonce then | 87 if not self.state.name or not self.state.clientnonce then |
83 end | 89 end |
84 self.state["servernonce"] = generate_uuid(); | 90 self.state["servernonce"] = generate_uuid(); |
85 self.state["salt"] = generate_uuid(); | 91 self.state["salt"] = generate_uuid(); |
86 | 92 |
87 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i; | 93 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i; |
94 self.state["server_first_message"] = server_first_message; | |
88 return "challenge", server_first_message | 95 return "challenge", server_first_message |
89 else | 96 else |
97 if type(message) ~= "string" then return "failure", "malformed-request" end | |
90 -- we are processing client_final_message | 98 -- we are processing client_final_message |
91 local client_final_message = message; | 99 local client_final_message = message; |
92 | 100 |
93 self.state["proof"] = client_final_message:match("p=(.+)"); | 101 self.state["proof"] = client_final_message:match("p=(.+)"); |
94 self.state["nonce"] = client_final_message:match("r=(.+),p="); | 102 self.state["nonce"] = client_final_message:match("r=(.+),p="); |
106 | 114 |
107 local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i) | 115 local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i) |
108 local ClientKey = hmac_sha1(SaltedPassword, "Client Key") | 116 local ClientKey = hmac_sha1(SaltedPassword, "Client Key") |
109 local ServerKey = hmac_sha1(SaltedPassword, "Server Key") | 117 local ServerKey = hmac_sha1(SaltedPassword, "Server Key") |
110 local StoredKey = sha1(ClientKey) | 118 local StoredKey = sha1(ClientKey) |
111 local AuthMessage = "n=" .. s_match(client_first_message,"n=(.+)") .. "," .. server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") | 119 local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") |
112 local ClientSignature = hmac_sha1(StoredKey, AuthMessage) | 120 local ClientSignature = hmac_sha1(StoredKey, AuthMessage) |
113 local ClientProof = binaryXOR(ClientKey, ClientSignature) | 121 local ClientProof = binaryXOR(ClientKey, ClientSignature) |
114 local ServerSignature = hmac_sha1(ServerKey, AuthMessage) | 122 local ServerSignature = hmac_sha1(ServerKey, AuthMessage) |
115 | 123 |
116 if base64.encode(ClientProof) == self.state.proof then | 124 if base64.encode(ClientProof) == self.state.proof then |
117 local server_final_message = "v="..base64.encode(ServerSignature); | 125 local server_final_message = "v="..base64.encode(ServerSignature); |
126 self["username"] = self.state.name; | |
118 return "success", server_final_message; | 127 return "success", server_final_message; |
119 else | 128 else |
120 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; | 129 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; |
121 end | 130 end |
122 end | 131 end |