From 1b8150580f834192929b0c9fbbabec98570e4088 Mon Sep 17 00:00:00 2001 From: b1galez Date: Sat, 2 Oct 2010 09:23:56 +0000 Subject: Version 1.0 git-svn-id: http://yubico-yubiserve.googlecode.com/svn/trunk@3 fbcee277-3294-991b-8290-beb7048acdd6 --- yubiserve.php | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 yubiserve.php (limited to 'yubiserve.php') diff --git a/yubiserve.php b/yubiserve.php new file mode 100644 index 0000000..946a8fa --- /dev/null +++ b/yubiserve.php @@ -0,0 +1,88 @@ + +Version 1.0: 21/05/2010 + +Licensed under GPL License (see LICENSE file) + +*/ + +require_once 'yubiserve-config.php'; +require_once 'yubiserve-utils.php'; + +if (!isset($_REQUEST["otp"])) + die ("ERR Missing OTP\n"); +$otp = trim($_REQUEST["otp"]); + +if ((strlen($otp)<32) || (strlen($otp)>48)) { + syslog(LOG_INFO, "Malformed OTP: $otp"); + die ("ERR Malformed OTP\n"); +} + +if (!preg_match("/^([cbdefghijklnrtuv]{0,16})([cbdefghijklnrtuv]{32})$/", $otp, $matches)) { + syslog(LOG_INFO, "Invalid OTP format: $otp"); + die("ERR Invalid OTP format\n"); + } + +$id = $matches[1]; +$modhex_ciphertext = $matches[2]; + +$results = @$db->query("SELECT aeskey, internalname FROM yubikeys WHERE publicname = '$id' AND active = 'true'"); +if ($results === false) { + syslog(LOG_INFO, "Unknown yubikey (internalname: $id)"); + die("ERR Unknown yubikey\n"); +} + +$row = $results->fetchAll(SQLITE_ASSOC); +if (count($row)>1) { + syslog(LOG_INFO, "Multiple keys returned! OTP: $otp"); + die("ERR Malformed OTP"); +} elseif (count($row)<1) { + syslog(LOG_INFO, "Unknown yubikey (internalname: $id)"); + die("ERR Unknown yubikey\n"); +} + +$aeskey = $row[0]['aeskey']; +$internalname = $row[0]['internalname']; + +$ciphertext = modhex2hex($modhex_ciphertext); +$plaintext = aes128ecb_decrypt($aeskey, $ciphertext); + +$uid = substr($plaintext, 0, 12); +if (strcmp($uid, $internalname) != 0) { + syslog(LOG_ERR, "UID error: $otp $plaintext: $uid vs $internalname"); + die("ERR Corrupt OTP\n"); +} + +if (!crc_is_good($plaintext)) { + syslog(LOG_ERR, "CRC error: $otp: $plaintext"); + die("ERR Corrupt OTP\n"); +} + +$counter = substr($plaintext, 14, 2) . substr($plaintext, 12, 2); +$low = substr($plaintext, 18, 2) . substr($plaintext, 16, 2); +$high = substr($plaintext, 20, 2); +$use = substr($plaintext, 22, 2); + +$timestamp = hexdec($high . $low); +$internalcounter = hexdec($counter . $use); + +#print("$counter $use $high $low\n"); + +$results = @$db->query("SELECT counter, time FROM yubikeys WHERE publicname = '$id' AND active = 'true' AND counter < $internalcounter"); +$row = @$results->fetchAll(SQLITE_ASSOC); + +if (count($row)!=1) { + syslog(LOG_ERR, "REPLAYED OTP for yubikey $id (same counter)"); + die("ERR Replayed OTP"); +} elseif ((($row[0] >> 8) == ($internalcounter >> 8)) && ($row[1] <= $timestamp)) { + syslog(LOG_ERR, "REPLAYED OTP for yubikey $id (same timestamp)"); + die("ERR Replayed OTP"); +} + +print "OK Authentication success"; +$results = $db->query("UPDATE yubikeys SET counter = $internalcounter, time = $timestamp WHERE publicname = '$id'"); + +unset($db); +?> -- cgit v1.2.3