Fail if username or password don't pass SASLprep.
[prosody.git] / util / sasl / scram.lua
index a347e2f3b98a3969e115a9e3d22764260668d62e..f7b8300accf91cd273d47894e55955d1a36c6fb0 100644 (file)
@@ -19,8 +19,10 @@ local xor = require "bit".bxor
 local hmac_sha1 = require "util.hmac".sha1;
 local sha1 = require "util.hashes".sha1;
 local generate_uuid = require "util.uuid".generate;
+local saslprep = require "util.encodings".stringprep.saslprep;
+local log = require "util.logger".init("sasl");
 
-module "plain"
+module "scram"
 
 --=========================
 --SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10
@@ -68,8 +70,11 @@ local function validate_username(username)
        end
        
        -- replace =2D with , and =3D with =
+       username:gsub("=2D", ",");
+       username:gsub("=3D", "=");
        
        -- apply SASLprep
+       username = saslprep(username);
        return username;
 end
 
@@ -83,10 +88,16 @@ local function scram_sha_1(self, message)
                self.state["name"] = client_first_message:match("n=(.+),r=")
                self.state["clientnonce"] = client_first_message:match("r=([^,]+)")
                
-               self.state.name = validate_username(self.state.name);
                if not self.state.name or not self.state.clientnonce then
                        return "failure", "malformed-request";
                end
+               
+               self.state.name = validate_username(self.state.name);
+               if not self.state.name then
+                       log("debug", "Username violates either SASLprep or contains forbidden character sequences.")
+                       return "failure", "malformed-request";
+               end
+               
                self.state["servernonce"] = generate_uuid();
                self.state["salt"] = generate_uuid();
                
@@ -110,6 +121,11 @@ local function scram_sha_1(self, message)
                        password, state = self.profile.plain(self.state.name, self.realm)
                        if state == nil then return "failure", "not-authorized"
                        elseif state == false then return "failure", "account-disabled" end
+                       password = saslprep(password);
+                       if not password then
+                               log("debug", "Password violates SASLprep.");
+                               return "failure", "not-authorized"
+                       end
                end
                
                local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i)