1
0
mirror of https://github.com/Yubico/yubikey-val.git synced 2025-01-19 16:52:15 +01:00

1. Nonce introduced in protocol. This required changes in the chain from client->verify->sync.

2. ykval-verify is modified a bit. It now acts more as a flow controller and relies on ykval-synclib 
to do details on DB-calls and counterlogic. The "system" decision making is still located in ykval-verify.
This commit is contained in:
Olov Danielson 2009-12-15 10:17:51 +00:00
parent 7be831db12
commit 6788e5effa
7 changed files with 262 additions and 216 deletions

View File

@ -121,6 +121,7 @@ class Db
public function connect(){
if (! $this->db_conn = mysql_connect($this->host, $this->user, $this->pwd)) {
error_log('Could not connect: ' . mysql_error());
$this->db_conn=Null;
return false;
}
if (! mysql_select_db($this->db_name)) {
@ -180,7 +181,7 @@ class Db
{
foreach ($values as $key=>$value){
if ($value != null) $query = $query . " " . $key . "='" . $value . "',";
$query = $query . " " . $key . "='" . $value . "',";
}
if (! $query) {
log("no values to set in query. Not updating DB");
@ -190,6 +191,7 @@ class Db
$query = rtrim($query, ",") . " WHERE id = " . $id . " and " . $condition;
// Insert UPDATE statement at beginning
$query = "UPDATE " . $table . " SET " . $query;
error_log("query is " . $query);
if (! mysql_query($query)){
error_log('Query failed: ' . mysql_error());
error_log('Query was: ' . $query);

View File

@ -102,6 +102,27 @@ class SyncLibTest extends PHPUnit_Framework_TestCase
$this->assertTrue($sl->countersHigherThanOrEqual($otpParams, $localParams));
}
public function testCountersEqual()
{
$sl = new SyncLib();
$localParams=array('yk_counter'=>100,
'yk_use'=>10);
$otpParams=array('yk_counter'=>100,
'yk_use'=>10);
$this->assertTrue($sl->countersEqual($otpParams, $localParams));
$otpParams['yk_use']=8;
$this->assertFalse($sl->countersEqual($otpParams, $localParams));
$otpParams['yk_use']=9;
$this->assertFalse($sl->countersEqual($otpParams, $localParams));
$otpParams['yk_use']=-11;
$this->assertFalse($sl->countersEqual($otpParams, $localParams));
$otpParams['yk_use']=10;
$otpParams['yk_counter']=101;
$this->assertFalse($sl->countersEqual($otpParams, $localParams));
}
public function testSync1()
{

View File

@ -10,6 +10,7 @@ define('S_NO_SUCH_CLIENT', 'NO_SUCH_CLIENT');
define('S_OPERATION_NOT_ALLOWED', 'OPERATION_NOT_ALLOWED');
define('S_BACKEND_ERROR', 'BACKEND_ERROR');
define('S_NOT_ENOUGH_ANSWERS', 'NOT_ENOUGH_ANSWERS');
define('S_REPLAYED_REQUEST', 'REPLAYED_REQUEST');
define('TS_SEC', 1/8);

View File

@ -41,7 +41,7 @@ CREATE TABLE queue (
-- DROP USER 'ykval_verifier'@'localhost';
CREATE USER 'ykval_verifier'@'localhost';
GRANT SELECT,INSERT,UPDATE(accessed, counter, low, high, sessionUse)
GRANT SELECT,INSERT,UPDATE(accessed, counter, low, high, sessionUse, nonce)
ON ykval.yubikeys to 'ykval_verifier'@'localhost';
GRANT SELECT(id, secret, active)
ON ykval.clients to 'ykval_verifier'@'localhost';

View File

@ -1,6 +1,7 @@
<?php
require_once 'ykval-common.php';
require_once 'ykval-config.php';
require_once 'ykval-synclib.php';
$apiKey = '';
@ -8,29 +9,24 @@ header("content-type: text/plain");
debug("Request: " . $_SERVER['QUERY_STRING']);
$conn = mysql_connect($baseParams['__YKVAL_DB_HOST__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__']);
if (!$conn) {
$sync = new SyncLib('ykval-sync');
if (! $sync->isConnected()) {
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
if (!mysql_select_db($baseParams['__YKVAL_DB_NAME__'], $conn)) {
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
}
#
# Define requirements on protocoll
#
$syncParams=array("modified"=>Null,
"otp"=>Null,
"yk_identity"=>Null,
"yk_counter"=>Null,
"yk_use"=>Null,
"yk_high"=>Null,
"yk_low"=>Null);
$syncParams=array('modified'=>Null,
'otp'=>Null,
'nonce'=>Null,
'yk_identity'=>Null,
'yk_counter'=>Null,
'yk_use'=>Null,
'yk_high'=>Null,
'yk_low'=>Null);
#
# Extract values from HTTP request
@ -53,34 +49,20 @@ debug($tmp_log);
# Get local counter data
#
$devId = $syncParams['yk_identity'];
$ad = getAuthData($conn, $devId);
if (!is_array($ad)) {
debug('Discovered Yubikey ' . $devId);
addNewKey($conn, $devId);
$ad = getAuthData($conn, $devId);
if (!is_array($ad)) {
debug('Invalid Yubikey ' . $devId);
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
$yk_identity = $syncParams['yk_identity'];
$localParams = $sync->getLocalParams($yk_identity);
if (!$localParams) {
debug('Invalid Yubikey ' . $yk_identity);
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
debug("Auth data:", $ad);
if ($ad['active'] != 1) {
debug('De-activated Yubikey ' . $devId);
if ($localParams['active'] != 1) {
debug('De-activated Yubikey ' . $yk_identity);
sendResp(S_BAD_OTP, $apiKey);
exit;
}
# Note: AD comes directly from the DB response. Since we want to separate
# DB-dependencies longterm, we parse out the values we want from the response
# in order to keep naming consistent in the remaining code. This could be
# considered inefficent in terms of computing power.
$localParams=array('modified'=>DbTimeToUnix($ad['accessed']),
'yk_counter'=>$ad['counter'],
'yk_use'=>$ad['sessionUse'],
'yk_low'=>$ad['low'],
'yk_high'=>$ad['high']);
#
# Compare sync and local counters and generate warnings according to
@ -88,57 +70,42 @@ $localParams=array('modified'=>DbTimeToUnix($ad['accessed']),
# http://code.google.com/p/yubikey-val-server-php/wiki/ServerReplicationProtocol
#
if ($syncParams['yk_counter'] > $localParams['yk_counter'] ||
($syncParams['yk_counter'] == $localParams['yk_counter'] &&
$syncParams['yk_use'] > $localParams['yk_use'])) {
# sync counters are higher than local counters. We should update database
#TODO: Take care of accessed field. What format should be used. seconds since epoch?
$stmt = 'UPDATE yubikeys SET ' .
'accessed=\'' . UnixToDbTime($syncParams['modified']) . '\'' .
', counter=' . $syncParams['yk_counter'] .
', sessionUse=' . $syncParams['yk_use'] .
', low=' . $syncParams['yk_low'] .
', high=' . $syncParams['yk_high'] .
' WHERE id=' . $ad['id'];
query($conn, $stmt);
} else {
if ($syncParams['yk_counter']==$localParams['yk_counter'] &&
$syncParams['yk_use']==$localParams['yk_use']) {
# sync counters are equal to local counters.
if ($syncParams['modified']==$localParams['modified']) {
# sync modified is equal to local modified. Sync request is unnessecarily sent, we log a "light" warning
error_log("ykval-sync:notice:Sync request unnessecarily sent");
} else {
# sync modified is not equal to local modified. We have an OTP replay attempt somewhere in the system
error_log("ykval-sync:warning:Replayed OTP attempt. " .
" identity=" . $syncParams['yk_identity'] .
" otp=" . $syncParams['otp'] .
" syncCounter=" . $syncParams['yk_counter'] .
" syncUse=" . $syncParams['yk_use'] .
" syncModified=" . $syncParams['modified'] .
" localModified=" . $localParams['modified']);
}
/* Conditional update local database */
$sync->updateDbCounters($syncParams);
if ($sync->countersHigherThan($localParams, $syncParams)) {
/* sync counters are lower than local counters */
$sync->log('warning', 'Remote server out of sync. Local params ' , $localParams);
$sync->log('warning', 'Remote server out of sync. Sync params ' , $syncParams);
}
if ($sync->countersEqual($localParams, $syncParams)) {
/* sync counters are equal to local counters. */
if ($syncParams['modified']==$localParams['modified']) {
/* sync modified is equal to local modified.
Sync request is unnessecarily sent, we log a "light" warning */
$sync->log('warning', 'Sync request unnessecarily sent');
} else {
# sync counters are lower than local counters
error_log("ykval-sync:warning:Remote server is out of sync." .
" identity=" . $syncParams['yk_identity'] .
" syncCounter=" . $syncParams['yk_counter'] .
" syncUse=" . $syncParams['yk_use'].
" localCounter=" . $localParams['yk_counter'] .
" localUse=" . $localParams['yk_use']);
/* sync modified is not equal to local modified.
We have an OTP replay attempt somewhere in the system */
$sync->log('warning', 'Replayed OTP attempt. Modified differs. Local ', $localParams);
$sync->log('warning', 'Replayed OTP attempt. Modified differs. Sync ', $syncParams);
}
if ($syncParams['nonce']!=$localParams['nonce']) {
$sync->log('warning', 'Replayed OTP attempt. Nonce differs. Local ', $localParams);
$sync->log('warning', 'Replayed OTP attempt. Nonce differs. Sync ', $syncParams);
}
}
$extra=array('modified'=>$localParams['modified'],
'yk_identity'=>$syncParams['yk_identity'], #NOTE: Identity is never picked out from local db
'yk_counter'=>$localParams['yk_counter'],
'yk_use'=>$localParams['yk_use'],
'yk_high'=>$localParams['yk_high'],
'yk_low'=>$localParams['yk_low']);
$extra=array('modified'=>$localParams['modified'],
'nonce'=>$localParams['nonce'],
'yk_identity'=>$yk_identity,
'yk_counter'=>$localParams['yk_counter'],
'yk_use'=>$localParams['yk_use'],
'yk_high'=>$localParams['yk_high'],
'yk_low'=>$localParams['yk_low']);
sendResp(S_OK, '', $extra);
sendResp(S_OK, '', $extra);
?>

View File

@ -9,21 +9,27 @@ class SyncLib
public $syncServers = null;
public $dbConn = null;
function __construct()
function __construct($logname='ykval-synclib')
{
$this->logname=$logname;
global $baseParams;
$this->syncServers = explode(";", $baseParams['__YKVAL_SYNC_POOL__']);
$this->db=new Db($baseParams['__YKVAL_DB_HOST__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_NAME__']);
$this->db->connect();
$this->isConnected=$this->db->connect();
$this->random_key=rand(0,1<<16);
$this->max_url_chunk=$baseParams['__YKVAL_SYNC_MAX_SIMUL__'];
$this->resync_timeout=$baseParams['__YKVAL_SYNC_RESYNC_TIMEOUT__'];
}
function isConnected()
{
return $this->isConnected;
}
function DbTimeToUnix($db_time)
{
$unix=strptime($db_time, '%F %H:%M:%S');
@ -39,13 +45,24 @@ class SyncLib
if (isset($this->syncServers[$index])) return $this->syncServers[$index];
else return "";
}
function getClientData($client)
{
$res=$this->db->customQuery('SELECT id, secret FROM clients WHERE active AND id='.mysql_quote($client));
if(mysql_num_rows($res)>0) {
$row = mysql_fetch_assoc($res);
mysql_free_result($res);
return $row;
} else return false;
}
function getLast()
{
$res=$this->db->last('queue', 1);
$info=$this->otpParamsFromInfoString($res['info']);
return array('modified'=>$this->DbTimeToUnix($res['modified_time']),
'otp'=>$res['otp'],
'server'=>$res['server'],
'server'=>$res['server'],
'nonce'=>$info['nonce'],
'yk_identity'=>$info['yk_identity'],
'yk_counter'=>$info['yk_counter'],
'yk_use'=>$info['yk_use'],
@ -64,6 +81,7 @@ class SyncLib
'&yk_use=' . $otpParams['yk_use'] .
'&yk_high=' . $otpParams['yk_high'] .
'&yk_low=' . $otpParams['yk_low'] .
'&nonce=' . $otpParams['nonce'] .
',local_counter=' . $localParams['yk_counter'] .
'&local_use=' . $localParams['yk_use'];
}
@ -108,33 +126,61 @@ class SyncLib
else return 0;
}
private function log($level, $msg, $params=NULL)
public function log($level, $msg, $params=NULL)
{
$logMsg="ykval-synclib:" . $level . ":" . $msg;
if ($params) $logMsg .= " modified=" . $params['modified'] .
" yk_identity=" . $params['yk_identity'] .
" yk_counter=" . $params['yk_counter'] .
" yk_use=" . $params['yk_use'] .
" yk_high=" . $params['yk_high'] .
" yk_low=" . $params['yk_low'];
$logMsg=$this->logname . ':' . $level . ':' . $msg;
if ($params) $logMsg .= ' modified=' . $params['modified'] .
' nonce=' . $params['nonce'] .
' yk_identity=' . $params['yk_identity'] .
' yk_counter=' . $params['yk_counter'] .
' yk_use=' . $params['yk_use'] .
' yk_high=' . $params['yk_high'] .
' yk_low=' . $params['yk_low'];
error_log($logMsg);
}
private function getLocalParams($yk_identity)
function updateLocalParams($id,$params)
{
return $this->db->update('yubikeys',
$id,
array('accessed'=>UnixToDbTime($params['modified']),
'nonce'=>$params['nonce'],
'counter'=>$params['yk_counter'],
'sessionUse'=>$params['yk_use'],
'high'=>$params['yk_high'],
'low'=>$params['yk_low']));
}
function getLocalParams($yk_identity)
{
$this->log("notice", "searching for " . $yk_identity . " (" . modhex2b64($yk_identity) . ") in local db");
$res = $this->db->lastBy('yubikeys', 'publicName', modhex2b64($yk_identity));
$localParams=array('modified'=>$this->DbTimeToUnix($res['accessed']),
'otp'=>$res['otp'],
'yk_identity'=>$yk_identity,
'yk_counter'=>$res['counter'],
'yk_use'=>$res['sessionUse'],
'yk_high'=>$res['high'],
'yk_low'=>$res['low']);
$this->log("notice", "counter found in db ", $localParams);
return $localParams;
$res = $this->db->findBy('yubikeys', 'publicName', modhex2b64($yk_identity),1);
if (!$res) {
$this->log('notice', 'Discovered new identity ' . $yk_identity);
$this->db->save('yubikeys', array('publicName'=>modhex2b64($yk_identity),
'active'=>1,
'counter'=>0,
'sessionUse'=>0,
'nonce'=>0));
$res=$this->db->findBy('yubikeys', 'publicName', modhex2b64($yk_identity), 1);
}
if ($res) {
$localParams=array('id'=>$res['id'],
'modified'=>$this->DbTimeToUnix($res['accessed']),
'otp'=>$res['otp'],
'nonce'=>$res['nonce'],
'active'=>$res['active'],
'yk_identity'=>$yk_identity,
'yk_counter'=>$res['counter'],
'yk_use'=>$res['sessionUse'],
'yk_high'=>$res['high'],
'yk_low'=>$res['low']);
$this->log("notice", "counter found in db ", $localParams);
return $localParams;
} else {
$this->log('notice', 'params for identity ' . $yk_identity . ' not found in database');
return false;
}
}
private function parseParamsFromMultiLineString($str)
@ -151,6 +197,8 @@ class SyncLib
$resParams['yk_high']=$out[1];
preg_match("/^yk_low=([0-9]*)/m", $str, $out);
$resParams['yk_low']=$out[1];
preg_match("/^nonce=([[:alpha:]]*)/m", $str, $out);
$resParams['nonce']=$out[1];
return $resParams;
}
@ -167,7 +215,8 @@ class SyncLib
'counter'=>$params['yk_counter'],
'sessionUse'=>$params['yk_use'],
'low'=>$params['yk_low'],
'high'=>$params['yk_high']),
'high'=>$params['yk_high'],
'nonce'=>$params['nonce']),
$condition))
{
error_log("ykval-synclib:critical: failed to update internal DB with new counters");
@ -195,7 +244,9 @@ class SyncLib
$p1['yk_use'] >= $p2['yk_use'])) return true;
else return false;
}
public function countersEqual($p1, $p2) {
return ($p1['yk_counter']==$p2['yk_counter']) && ($p1['yk_use']==$p2['yk_use']);
}
public function deleteQueueEntry($answer)
{
@ -285,16 +336,18 @@ class SyncLib
$this->log("warning", "queued:Local server out of sync, local counters ", $localParams);
$this->log("warning", "queued:Local server out of sync, remote counters ", $resParams);
}
/* If received sync response have higher counters than OTP counters
(indicating REPLAYED_OTP)
*/
if ($this->countersHigherThanOrEqual($resParams, $otpParams)) {
$this->log('critical', 'queued:replayed OTP, queued sync request indicated OTP as invalid');
if ($this->countersHigherThan($resParams, $otpParams) ||
($this->countersEqual($resParams, $otpParams) &&
$resParams['nonce']!=$otpParams['nonce'])) {
/* If received sync response have higher counters than OTP or same counters with different nonce
(indicating REPLAYED_OTP)
*/
$this->log("warning", "queued:replayed OTP, remote counters " , $resParams);
$this->log("warning", "queued:replayed OTP, otp counters", $otpParams);
}
/* Deletion */
$this->log('notice', 'deleting queue entry with id=' . $entry['id']);
@ -349,33 +402,41 @@ class SyncLib
/* Check for warnings
If received sync response have lower counters than locally saved
last counters (indicating that remote server wasn't synced)
If received sync response have lower counters than local db
(indicating that remote server wasn't synced)
*/
if ($this->countersHigherThan($localParams, $resParams)) {
$this->log("warning", "Remote server out of sync, local counters ", $localParams);
$this->log("warning", "Remote server out of sync, remote counters ", $resParams);
}
/* If received sync response have higher counters than locally saved
last counters (indicating that local server wasn't synced)
/* If received sync response have higher counters than local db
(indicating that local server wasn't synced)
*/
if ($this->countersHigherThan($resParams, $localParams)) {
$this->log("warning", "Local server out of sync, local counters ", $localParams);
$this->log("warning", "Local server out of sync, remote counters ", $resParams);
}
/* If received sync response have higher counters than OTP counters
(indicating REPLAYED_OTP)
*/
if ($this->countersHigherThanOrEqual($resParams, $this->otpParams)) {
if ($this->countersHigherThan($resParams, $this->otpParams) ||
($this->countersEqual($resParams, $this->otpParams) &&
$resParams['nonce']!=$this->otpParams['nonce'])) {
/* If received sync response have higher counters than OTP or same counters with different nonce
(indicating REPLAYED_OTP)
*/
$this->log("warning", "replayed OTP, remote counters " , $resParams);
$this->log("warning", "replayed OTP, otp counters", $this->otpParams);
} else {
/* The answer is ok since a REPLAY was not indicated */
$this->valid_answers++;
}
/* Check if answer marks OTP as valid */
if (!$this->countersHigherThanOrEqual($resParams, $this->otpParams)) $this->valid_answers++;
/* Delete entry from table */
$this->deleteQueueEntry($answer);

View File

@ -9,34 +9,47 @@ header("content-type: text/plain");
debug("Request: " . $_SERVER['QUERY_STRING']);
$protocol_version=2.0;
if (preg_match("/\/wsapi\/([0-9]*)\.([0-9]*)\//", $_SERVER['REQUEST_URI'], $out)) {
$protocol_version=$out[1]+$out[2]*0.1;
} else {
$protocol_version=1.0;
}
debug("found protocol version " . $protocol_version);
$conn = mysql_connect($baseParams['__YKVAL_DB_HOST__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__']);
if (!$conn) {
/* Initialize the sync library. Strive to use this instead of custom DB requests,
custom comparisons etc */
$sync = new SyncLib();
if (! $sync->isConnected()) {
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
if (!mysql_select_db($baseParams['__YKVAL_DB_NAME__'], $conn)) {
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
}
//// Extract values from HTTP request
//
/* Extract values from HTTP request
*/
$h = getHttpVal('h', '');
$client = getHttpVal('id', 0);
$otp = getHttpVal('otp', '');
$otp = strtolower($otp);
$timestamp = getHttpVal('timestamp', 0);
if ($protocol_version>=2.0) {
$sl = getHttpVal('sl', '');
$timeout = getHttpVal('timeout', '');
$nonce = getHttpVal('nonce', '');
/* Nonce is required from protocol 2.0 */
if(!$nonce || strlen($nonce)<16) {
debug('Protocol version >= 2.0. Nonce is missing');
sendResp(S_MISSING_PARAMETER, $apiKey);
exit;
}
}
if ($protocol_version<2.0) {
/* We need to create a nonce manually here */
$nonce = md5(uniqid(rand()));
debug('protocol version below 2.0. Created nonce ' . $nonce);
}
//// Get Client info from DB
//
if ($client <= 0) {
@ -45,12 +58,12 @@ if ($client <= 0) {
exit;
}
$cd = getClientData($conn, $client);
if ($cd == null) {
$cd=$sync->getClientData($client);
if(!$cd) {
debug('Invalid client id ' . $client);
sendResp(S_NO_SUCH_CLIENT);
exit;
}
}
debug("Client data:", $cd);
//// Check client signature
@ -66,7 +79,8 @@ if ($h != '') {
if ($timestamp) $a['timestamp'] = $timestamp;
if ($sl) $a['sl'] = $sl;
if ($timeout) $a['timeout'] = $timeout;
if ($nonce) $a['nonce'] = $nonce;
$hmac = sign($a, $apiKey);
// Compare it
if ($hmac != $h) {
@ -109,89 +123,58 @@ debug("Decrypted OTP:", $otpinfo);
//// Get Yubikey from DB
//
$devId = substr($otp, 0, strlen ($otp) - TOKEN_LEN);
$ad = getAuthData($conn, $devId);
if (!is_array($ad)) {
debug('Discovered Yubikey ' . $devId);
addNewKey($conn, $devId);
$ad = getAuthData($conn, $devId);
if (!is_array($ad)) {
debug('Invalid Yubikey ' . $devId);
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
}
debug("Auth data:", $ad);
if ($ad['active'] != 1) {
$yk_identity=$devId;
$localParams = $sync->getLocalParams($yk_identity);
if (!$localParams) {
debug('Invalid Yubikey ' . $yk_identity);
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
debug("Auth data:", $localParams);
if ($localParams['active'] != 1) {
debug('De-activated Yubikey ' . $devId);
sendResp(S_BAD_OTP, $apiKey);
exit;
}
//// Check the session counter
//
$sessionCounter = $otpinfo["session_counter"]; // From the req
$seenSessionCounter = $ad['counter']; // From DB
if ($sessionCounter < $seenSessionCounter) {
debug("Replay, session counter, seen=" . $seenSessionCounter .
" this=" . $sessionCounter);
sendResp(S_REPLAYED_OTP, $apiKey);
exit;
}
/* Build OTP params */
//// Check the session use
//
$sessionUse = $otpinfo["session_use"]; // From the req
$seenSessionUse = $ad['sessionUse']; // From DB
if ($sessionCounter == $seenSessionCounter && $sessionUse <= $seenSessionUse) {
debug("Replay, session use, seen=" . $seenSessionUse .
' this=' . $sessionUse);
sendResp(S_REPLAYED_OTP, $apiKey);
exit;
}
//// Valid OTP, update database
//
$stmt = 'UPDATE yubikeys SET accessed=NOW()' .
', counter=' .$otpinfo['session_counter'] .
', sessionUse=' . $otpinfo['session_use'] .
', low=' . $otpinfo['low'] .
', high=' . $otpinfo['high'] .
' WHERE id=' . $ad['id'];
$r=query($conn, $stmt);
$stmt = 'SELECT accessed FROM yubikeys WHERE id=' . $ad['id'];
$r=query($conn, $stmt);
if (mysql_num_rows($r) > 0) {
$row = mysql_fetch_assoc($r);
mysql_free_result($r);
$modified=DbTimeToUnix($row['accessed']);
}
else {
$modified=0;
}
//// Queue sync requests
$sync = new SyncLib();
// We need the modifed value from the DB
$stmp = 'SELECT accessed FROM yubikeys WHERE id=' . $ad['id'];
query($conn, $stmt);
$otpParams=array('modified'=>$modified,
$otpParams=array('modified'=>time(),
'otp'=>$otp,
'nonce'=>$nonce,
'yk_identity'=>$devId,
'yk_counter'=>$otpinfo['session_counter'],
'yk_use'=>$otpinfo['session_use'],
'yk_high'=>$otpinfo['high'],
'yk_low'=>$otpinfo['low']);
$localParams=array('modified'=>DbTimeToUnix($ad['accessed']),
'otp'=>'',
'yk_identity'=>$devId,
'yk_counter'=>$ad['counter'],
'yk_use'=>$ad['sessionUse'],
'yk_high'=>$ad['high'],
'yk_low'=>$ad['low']);
/* First check if OTP is seen with the same nonce, in such case we have an replayed request */
if ($sync->countersEqual($localParams, $otpParams) &&
$localParams['nonce']==$otpParams['nonce']) {
debug('Replayed request');
sendResp(S_REPLAYED_REQUEST, $apikey);
exit;
}
/* Check the OTP counters against local db */
if ($sync->countersHigherThanOrEqual($localParams, $otpParams)) {
$sync->log('warning', 'replayed OTP: Local counters higher');
$sync->log('warning', 'replayed OTP: Local counters ', $localParams);
$sync->log('warning', 'replayed OTP: Otp counters ', $otpParams);
sendResp(S_REPLAYED_OTP, $apiKey);
exit;
}
/* Valid OTP, update database. */
if(!$sync->updateDbCounters($otpParams)) {
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
/* Queue sync requests */
if (!$sync->queue($otpParams, $localParams)) {
debug("ykval-verify:critical:failed to queue sync requests");
@ -241,6 +224,16 @@ if($syncres==False) {
}
}
/* Recreate parameters to make phising test work out
TODO: use timefunctionality in deltatime library instead */
$sessionCounter = $otpParams['yk_counter'];
$sessionUse = $otpParams['yk_use'];
$seenSessionCounter = $localParams['yk_counter'];
$seenSessionUse = $localParams['yk_use'];
$ad['high']=$localParams['yk_high'];
$ad['low']=$localParams['yk_low'];
$ad['accessed']=$sync->unixToDbTime($localParams['modified']);
//// Check the time stamp
//
@ -285,6 +278,7 @@ $extra=array();
if ($protocol_version>=2.0) {
$extra['otp']=$otp;
$extra['sl'] = $sl_success_rate;
$extra['nonce']= $nonce;
}
if ($timestamp==1){
$extra['timestamp'] = ($otpinfo['high'] << 16) + $otpinfo['low'];