--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_auth_token/token_auth_utils.lib.lua Tue Mar 27 10:48:04 2018 +0200
@@ -0,0 +1,67 @@
+local base64 = require "util.encodings".base64;
+local digest = require "openssl.digest";
+local hmac = require "openssl.hmac";
+local luatz = require "luatz";
+local otp = require "otp";
+
+local DIGEST_TYPE = "SHA256";
+local OTP_DEVIATION = 1;
+local OTP_DIGITS = 8;
+local OTP_INTERVAL = 30;
+
+local nonce_cache = {};
+
+function check_nonce(jid, otp, nonce)
+ -- We cache all nonces used per OTP, to ensure that a token cannot be used
+ -- more than once.
+ --
+ -- We assume that the OTP is valid in the current time window. This is the
+ -- case because we only call check_nonce *after* the OTP has been verified.
+ --
+ -- We only store one OTP per JID, so if a new OTP comes in, we wipe the
+ -- previous OTP and its cached nonces.
+ if nonce_cache[jid] == nil or nonce_cache[jid][otp] == nil then
+ nonce_cache[jid] = {}
+ nonce_cache[jid][otp] = {}
+ nonce_cache[jid][otp][nonce] = true
+ return true;
+ end
+ if nonce_cache[jid][otp][nonce] == true then
+ return false;
+ else
+ nonce_cache[jid][otp][nonce] = true;
+ return true;
+ end
+end
+
+
+function verify_token(username, password, realm, otp_seed, token_secret, log)
+ local totp = otp.new_totp_from_key(otp_seed, OTP_DIGITS, OTP_INTERVAL)
+ local token = string.match(password, "(%d+) ")
+ local otp = token:sub(1,8)
+ local nonce = token:sub(9)
+ local signature = base64.decode(string.match(password, " (.+)"))
+ local jid = username.."@"..realm
+
+ if totp:verify(otp, OTP_DEVIATION, luatz.gmtime(luatz.time())) then
+ -- log("debug", "**** THE OTP WAS VERIFIED ****** ");
+ local hmac_ctx = hmac.new(token_secret, DIGEST_TYPE)
+ if signature == hmac_ctx:final(otp..nonce..jid) then
+ -- log("debug", "**** THE KEY WAS VERIFIED ****** ");
+ if check_nonce(jid, otp, nonce) then
+ -- log("debug", "**** THE NONCE WAS VERIFIED ****** ");
+ return true;
+ end
+ end
+ end
+ -- log("debug", "**** VERIFICATION FAILED ****** ");
+ return false;
+end
+
+return {
+ OTP_DEVIATION = OTP_DIGITS,
+ OTP_DIGITS = OTP_DIGITS,
+ OTP_INTERVAL = OTP_INTERVAL,
+ DIGEST_TYPE = DIGEST_TYPE,
+ verify_token = verify_token;
+}