diff --git a/common.php b/common.php index 92f5540..d35365b 100644 --- a/common.php +++ b/common.php @@ -8,6 +8,9 @@ define('S_MISSING_PARAMETER', 'MISSING_PARAMETER'); //define('S_NO_SUCH_CLIENT', 'NO_SUCH_CLIENT'); // Deprecated by paul 20080920 define('S_OPERATION_NOT_ALLOWED', 'OPERATION_NOT_ALLOWED'); define('S_BACKEND_ERROR', 'BACKEND_ERROR'); +define('S_SECURITY_ERROR', 'SECURITY_ERROR'); +define('TS_SEC', 0.1118); +define('TS_TOLERANCE', 0.3); function debug($msg, $exit = false) { global $trace; diff --git a/verifyOTP.php b/verifyOTP.php index 4bad970..0e4482b 100644 --- a/verifyOTP.php +++ b/verifyOTP.php @@ -1,10 +1,13 @@ - 0) { - debug("Replayed session counter=".$sessionCounter.', seen='.$seenSessionCounter); + debug("Replayed session counter=" . $sessionCounter . ', seen=' . $seenSessionCounter); sendResp(S_REPLAYED_OTP); exit; } else { - debug("Session counter OK (".$sessionCounter.")"); + debug("Session counter OK (" . $sessionCounter . ")"); +} + +//// Check the time stamp +// +if ($scDiff == 0) { // Same use session, check time stamp diff + $ts = $decoded_token['timestamp']; + $seenTs = ($ad['high'] << 16) + $ad['low']; + $tsDiff = $ts - $seenTs; + if ($tsDiff <= 0) { + debug("Replayed time stamp=" . $ts . ', seen=' . $seenTs); + sendResp(S_REPLAYED_OTP); + exit; + } else { + $tsDelta = $tsDiff * TS_SEC; + debug("Timestamp OK (" . $ts . ") delta count=".$tsDiff. + '-> delta secs='.$tsDelta); + } + + $lastTime = strtotime($ad['accessed']); + //$lastAccess = $ad['accessed']; + //echo 'Last accessed: '.$lastAccess.' '.date("F j, Y, g:i a", $lastTime)."\n"; + $elapsed = time() - $lastTime; + debug('Elapsed time from last validation: '.$elapsed.' secs'); + $deviation = abs($elapsed - $tsDelta); + debug("Key time deviation vs. real elapsed time=".$deviation.' secs'); + if ($deviation > TS_TOLERANCE * $elapsed) { + debug("Is the OTP generated from a real crypto key?"); + sendResp(S_SECURITY_ERROR); + exit; + } } //// Check the high counter // -$hi = $decoded_token["high"]; // From the req -$seenHi = $ad['high']; // From DB -$hiDiff = $seenHi - $hi; -if ($scDiff == 0 && $hiDiff > 0) { - debug("Replayed hi counter=".$hi.', seen='.$seenHi); - sendResp(S_REPLAYED_OTP); - exit; -} else { - debug("Hi counter OK (".$hi.")"); -} +//$hi = $decoded_token["high"]; // From the req +//$seenHi = $ad['high']; // From DB +//$hiDiff = $seenHi - $hi; +//if ($scDiff == 0 && $hiDiff > 0) { +// debug("Replayed hi counter=".$hi.', seen='.$seenHi); +// sendResp(S_REPLAYED_OTP); +// exit; +//} else { +// debug("Hi counter OK (".$hi.")"); +//} //// Check the low counter // -$lo = $decoded_token["low"]; // From the req -$seenLo = $ad['low']; // From DB -$loDiff = $seenLo - $lo; -if ($scDiff == 0 && $hiDiff == 0 && $loDiff >= 0) { - debug("Replayed low counter=".$lo.', seen='.$seenLo); - sendResp(S_REPLAYED_OTP); - exit; -} else { - debug("Lo counter OK (".$lo.")"); -} +//$lo = $decoded_token["low"]; // From the req +//$seenLo = $ad['low']; // From DB +//$loDiff = $seenLo - $lo; +//if ($scDiff == 0 && $hiDiff == 0 && $loDiff >= 0) { +// debug("Replayed low counter=".$lo.', seen='.$seenLo); +// sendResp(S_REPLAYED_OTP); +// exit; +//} else { +// debug("Lo counter OK (".$lo.")"); +//} //// Update the DB only upon validation success // if (updDB($ad['id'], $decoded_token, $client)) { - debug('Validation database updated'); + debug('Validation database updated'); sendResp(S_OK); } else { debug('Failed to update validation database'); @@ -166,41 +199,40 @@ if (updDB($ad['id'], $decoded_token, $client)) { // Functions ////////////////////////// -function sendResp($status, $info=null) { +function sendResp($status, $info = null) { global $ad, $apiKey; if ($status == null) { $status = S_BACKEND_ERROR; } - echo 'status='.($a['status'] = $status).PHP_EOL; + echo 'status=' . ($a['status'] = $status) . PHP_EOL; if ($info != null) { - echo 'info='.($a['info'] = $info).PHP_EOL; + echo 'info=' . ($a['info'] = $info) . PHP_EOL; } - echo 't='.($a['t']=getUTCTimeStamp()).PHP_EOL; + echo 't=' . ($a['t'] = getUTCTimeStamp()) . PHP_EOL; $h = sign($a, $apiKey); - echo 'h='.$h.PHP_EOL; + echo 'h=' . $h . PHP_EOL; echo PHP_EOL; } // End sendResp function updDB($keyid, $new, $client) { - $stmt = 'UPDATE yubikeys SET '. - 'accessed=NOW(),'. - 'counter='.$new['session_counter'].','. - 'low='.$new['low'].','. - 'high='.$new['high']. - ' WHERE id='.$keyid; + $stmt = 'UPDATE yubikeys SET ' . + 'accessed=NOW(),' . + 'counter=' . $new['session_counter'] . ',' . + 'low=' . $new['low'] . ',' . + 'high=' . $new['high'] . + ' WHERE id=' . $keyid; if (!query($stmt)) { - $err = 'Failed to update validation data of key: '.$keyid.' by '.$stmt; + $err = 'Failed to update validation data of key: ' . $keyid . ' by ' . $stmt; debug($err); writeLog($err); return false; } - addHist(0, $_SERVER['REMOTE_ADDR'] , $keyid, $client); + addHist(0, $_SERVER['REMOTE_ADDR'], $keyid, $client); return true; } - ?>