---
-- 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,
}