--- -- Simple Authentication and Security Layer (SASL). -- -- The library contains some low level functions and a high level class. -- -- The Helper class contains the high level methodes: -- * new: This is the SASL object constructor. -- * set_mechanism: Sets the authentication mechanism to use. -- * set_callback: Sets the encoding function to use. -- * encode: Encodes the parameters according to the -- authentication mechanism. -- * reset_callback: Resets the authentication function. -- * reset: Resets the SASL object. -- -- The script writers should use the Helper class to create SASL objects, -- and they can also use the low level functions to customize their -- encoding functions. -- -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html module(... or "sasl", package.seeall) local HAVE_SSL = false require 'stdnse' require 'base64' local MECHANISMS = { -- ["mechanism"] = callback function } if pcall(require, 'openssl') then HAVE_SSL = true else stdnse.print_debug(1, "sasl.lua: OpenSSL not present, SASL support limited.") end if HAVE_SSL then --- Encodes the parameters using the CRAM-MD5 mechanism. -- -- @param username string. -- @param password string. -- @param challenge The challenge as it is returned by the server. -- @return string The encoded string on success, or nil if Nmap was -- compiled without OpenSSL. function cram_md5_enc(username, password, challenge) local encode = stdnse.tohex(openssl.hmac('md5', password, base64.dec(challenge))) return base64.enc(username.." "..encode) end --- Encodes the parameters using the DIGEST-MD5 mechanism. -- -- @param username string. -- @param password string. -- @param realm string. -- @param challenge The challenge as it is returned by the server. -- @return string The encoded string on success, or nil if Nmap was -- compiled without OpenSSL. function digest_md5_enc(username, password, realm, challenge) local HA1 = openssl.md5(stdnse.strjoin(":", username, realm, password)) return nil end else function cram_md5_enc() return nil end function digest_md5_enc() return nil end end MECHANISMS["CRAM-MD5"] = cram_md5_enc MECHANISMS["DIGEST-MD5"] = digest_md5_enc --- Encodes the parameters using the LOGIN mechanism. -- -- @param username string. -- @param password string. -- @return username The encoded username. -- @return password the encoded password. function login_enc(username, password) return base64.enc(username), base64.enc(password) end MECHANISMS["LOGIN"] = login_enc --- Encodes the parameters using the PLAIN mechanism. -- -- @param username string. -- @param password string. -- @return string The encoded string. function plain_enc(username, password) return base64.enc(username.."\0"..username.."\0"..password) end MECHANISMS["PLAIN"] = plain_enc --- Checks if the given mechanism is supported by this library. -- -- @param mechanism string to check. -- @return mechanism if it is supported, otherwise nil. -- @return callback The mechanism encoding function on success. function check_mechanism(mechanism) local lmech, lcallback if mechanism then mechanism = string.upper(mechanism) if MECHANISMS[mechanism] then lmech = mechanism lcallback = MECHANISMS[mechanism] else stdnse.print_debug(3, "sasl library does not support '%s' mechanism", mechanism) end end return lmech, lcallback end --- This is the SASL Helper class, script writers should use it to create -- SASL objects. -- -- Usage of the Helper class: -- -- local sasl_enc = sasl.Helper.new("CRAM-MD5") -- local result = sasl_enc:encode(username, password, challenge) -- -- sasl_enc:set_mechanism("LOGIN") -- local user, pass = sasl_enc:encode(username, password) Helper = { --- SASL object constructor. -- -- @param mechanism The authentication mechanism to use -- (optional parameter). -- @param callback The encoding function associated with the -- mechanism (optional parameter). -- @usage -- local sasl_enc = sasl.Helper:new() -- local sasl_enc = sasl.Helper:new("CRAM-MD5") -- local sasl_enc = sasl.Helper:new("CRAM-MD5", my_cram_md5_func) -- @return sasl object. new = function(self, mechanism, callback) local o = {} setmetatable(o, self) self.__index = self if self:set_mechanism(mechanism) then self:set_callback(callback) end return o end, --- Sets the SASL mechanism to use. -- -- @param string The authentication mechanism. -- @usage -- local sasl_enc = sasl.Helper:new() -- sasl_enc:set_mechanism("CRAM-MD5") -- sasl_enc:set_mechanism("PLAIN") -- @return mechanism on success, or nil if the mechanism is not -- supported. set_mechanism = function(self, mechanism) self.mechanism, self.callback = check_mechanism(mechanism) return self.mechanism end, --- Associates A custom encoding function with the authentication -- mechanism. -- -- Note that the SASL object by default will have its own -- callback functions. -- -- @param callback The function associated with the authentication -- mechanism. -- @usage -- -- My personal CRAM-MD5 encode function -- function cram_md5_encode_func(username, password, challenge) -- ... -- end -- local sasl_enc = sasl.Helper:new("CRAM-MD5") -- sasl_enc:set_callback(cram_md5_handle_func) -- local result = sasl_enc:encode(username, password, challenge) set_callback = function(self, callback) if callback then self.callback = callback end end, --- Resets the encoding function to the default SASL -- callback function. reset_callback = function(self) self.callback = MECHANISMS[self.mechanism] end, --- Resets all the data of the SASL object. -- -- This methode will clear the specified SASL mechanism. reset = function(self) self:set_mechanism() end, --- Returns the current authentication mechanism. -- -- @return mechanism on success, or nil on failures. get_mechanism = function(self) return self.mechanism end, --- Encodes the parameters according to the specified mechanism. -- -- @param ... The parameters to encode. -- @usage -- local sasl_enc = sasl.Helper:new("CRAM-MD5") -- local result = sasl_enc:encode(username, password, challenge) -- local sasl_enc = sasl.Helper:new("PLAIN") -- local result = sasl_enc:encode(username, password) -- @return string The encoded string on success, or nil on failures. encode = function(self, ...) return self.callback(...) end, }