- local object = { mechanism = "DIGEST-MD5", onAuth = onAuth, onSuccess = onSuccess, onFail = onFail,
- onWrite = onWrite }
-
- --TODO: something better than math.random would be nice, maybe OpenSSL's random number generator
- object.nonce = generate_uuid()
- log("debug", "SASL nonce: "..object.nonce)
- object.step = 1
- object.nonce_count = {}
- local challenge = base64.encode(serialize({ nonce = object.nonce,
- qop = "auth",
- charset = "utf-8",
- algorithm = "md5-sess"} ));
- object.onWrite(st.stanza("challenge", {xmlns = "urn:ietf:params:xml:ns:xmpp-sasl"}):text(challenge))
- object.feed = function(self, stanza)
- log("debug", "SASL step: "..self.step)
- if stanza.name ~= "response" and stanza.name ~= "auth" then self.onFail("invalid-stanza-tag") end
- if stanza.attr.xmlns ~= "urn:ietf:params:xml:ns:xmpp-sasl" then self.onFail("invalid-stanza-namespace") end
- if stanza.name == "auth" then return end
- self.step = self.step + 1
- if (self.step == 2) then
- local response = parse(base64.decode(stanza[1]))
- -- check for replay attack
- if response["nc"] then
- if self.nonce_count[response["nc"]] then self.onFail("not-authorized") end
- end
-
- -- check for username, it's REQUIRED by RFC 2831
- if not response["username"] then
- self.onFail("malformed-request")
- end
- self["username"] = response["username"]
-
- -- check for nonce, ...
- if not response["nonce"] then
- self.onFail("malformed-request")
- else
- -- check if it's the right nonce
- if response["nonce"] ~= tostring(self.nonce) then self.onFail("malformed-request") end
- end
-
- if not response["cnonce"] then self.onFail("malformed-request") end
- if not response["qop"] then response["qop"] = "auth" end
-
- if response["realm"] == nil then response["realm"] = "" end
-
- local domain = ""
- local protocol = ""
- if response["digest-uri"] then
- protocol, domain = response["digest-uri"]:match("(%w+)/(.*)$")
- else
- error("No digest-uri")
- end
-
- -- compare response_value with own calculation
- --local A1 = usermanager.get_md5(response["username"], hostname)..":"..response["nonce"]..response["cnonce"]
-
- --FIXME actual username and password here :P
- local X = "tobias:"..response["realm"]..":tobias"
- local Y = md5.sum(X)
- local A1 = Y..":"..response["nonce"]..":"..response["cnonce"]--:authzid
- local A2 = "AUTHENTICATE:"..protocol.."/"..domain
-
- local HA1 = md5.sumhexa(A1)
- local HA2 = md5.sumhexa(A2)
-
- local KD = HA1..":"..response["nonce"]..":"..response["nc"]..":"..response["cnonce"]..":"..response["qop"]..":"..HA2
- local response_value = md5.sumhexa(KD)
-
- log("debug", "response_value: "..response_value);
- log("debug", "response: "..response["response"]);
- if response_value == response["response"] then
- -- calculate rspauth
- A2 = ":"..protocol.."/"..domain
-
- HA1 = md5.sumhexa(A1)
- HA2 = md5.sumhexa(A2)