1
0
mirror of https://github.com/Yubico/yubikey-val.git synced 2024-11-29 00:24:13 +01:00
yubikey-val/ykval-sync.php

191 lines
6.3 KiB
PHP
Raw Normal View History

2013-04-17 17:24:50 +02:00
<?php
2014-09-24 13:05:09 +02:00
# Copyright (c) 2009-2014 Yubico AB
2013-04-17 17:24:50 +02:00
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require_once 'ykval-common.php';
require_once 'ykval-config.php';
require_once 'ykval-synclib.php';
$apiKey = '';
$ipaddr = $_SERVER['REMOTE_ADDR'];
$allowed = $baseParams['__YKVAL_ALLOWED_SYNC_POOL__'];
2013-04-17 17:24:50 +02:00
header('content-type: text/plain');
2013-04-17 17:24:50 +02:00
$myLog = new Log('ykval-sync');
$myLog->addField('ip', $ipaddr);
2013-04-17 17:24:50 +02:00
if (empty($_SERVER['QUERY_STRING'])) {
2013-04-17 17:24:50 +02:00
sendResp(S_MISSING_PARAMETER, $myLog, $apiKey);
}
$myLog->log(LOG_INFO, 'Request: ' . $_SERVER['QUERY_STRING']);
2013-04-17 17:24:50 +02:00
$sync = new SyncLib('ykval-sync:synclib');
$sync->addField('ip', $ipaddr);
2013-04-17 17:24:50 +02:00
if (! $sync->isConnected()) {
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
}
#
# Verify that request comes from valid server
#
$myLog->log(LOG_DEBUG, 'Received request from ' . $ipaddr);
2013-04-17 17:24:50 +02:00
if (in_array($ipaddr, $allowed, TRUE) === FALSE) {
$myLog->log(LOG_NOTICE, 'Operation not allowed from IP ' . $ipaddr);
$myLog->log(LOG_DEBUG, 'Remote IP ' . $ipaddr . ' not listed in allowed sync pool : ' . implode(', ', $allowed));
2013-04-17 17:24:50 +02:00
sendResp(S_OPERATION_NOT_ALLOWED, $myLog, $apiKey);
}
#
# Define requirements on protocol
#
$syncParams = array(
2015-07-16 22:54:31 +02:00
'modified' => NULL,
'otp' => NULL,
'nonce' => NULL,
'yk_publicname' => NULL,
'yk_counter' => NULL,
'yk_use' => NULL,
'yk_high' => NULL,
'yk_low' => NULL
);
2013-04-17 17:24:50 +02:00
#
# Extract values from HTTP request
#
$tmp_log = "Received ";
foreach ($syncParams as $param=>$value) {
2015-07-16 22:54:31 +02:00
$value = getHttpVal($param, NULL);
if ($value==NULL) {
2013-04-17 17:24:50 +02:00
$myLog->log(LOG_NOTICE, "Received request with parameter[s] (" . $param . ") missing value");
sendResp(S_MISSING_PARAMETER, $myLog, $apiKey);
}
$syncParams[$param]=$value;
$tmp_log .= "$param=$value ";
}
$myLog->log(LOG_INFO, $tmp_log);
#
# At this point we should have the otp so let's add it to the logging module
#
$myLog->addField('otp', $syncParams['otp']);
$sync->addField('otp', $syncParams['otp']);
#
# Verify correctness of input parameters
#
foreach (array('modified','yk_counter', 'yk_use', 'yk_high', 'yk_low') as $param)
{
// -1 is valid except for modified
if ($param !== 'modified' && $syncParams[$param] === '-1')
continue;
// [0-9]+
if ($syncParams[$param] !== '' && ctype_digit($syncParams[$param]))
continue;
$myLog->log(LOG_NOTICE, 'Input parameters ' . $param . ' not correct');
sendResp(S_MISSING_PARAMETER, $myLog, $apiKey);
2013-04-17 17:24:50 +02:00
}
#
# Get local counter data
#
$yk_publicname = $syncParams['yk_publicname'];
$localParams = $sync->getLocalParams($yk_publicname);
if (!$localParams) {
$myLog->log(LOG_NOTICE, 'Invalid Yubikey ' . $yk_publicname);
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
}
/* Conditional update local database */
$sync->updateDbCounters($syncParams);
$myLog->log(LOG_DEBUG, 'Local params ', $localParams);
$myLog->log(LOG_DEBUG, 'Sync request params ', $syncParams);
2013-04-17 17:24:50 +02:00
/**
* Compare sync and local counters and generate warnings according to
* https://developers.yubico.com/yubikey-val/doc/ServerReplicationProtocol.html
*/
2013-04-17 17:24:50 +02:00
if ($sync->countersHigherThan($localParams, $syncParams)) {
$myLog->log(LOG_WARNING, 'Remote server out of sync.');
}
if ($sync->countersEqual($localParams, $syncParams)) {
if ($syncParams['modified']==$localParams['modified'] &&
$syncParams['nonce']==$localParams['nonce']) {
/* This is not an error. When the remote server received an OTP to verify, it would
* have sent out sync requests immediately. When the required number of responses had
* been received, the current implementation discards all additional responses (to
* return the result to the client as soon as possible). If our response sent last
* time was discarded, we will end up here when the background ykval-queue processes
* the sync request again.
*/
$myLog->log(LOG_INFO, 'Sync request unnecessarily sent');
}
if ($syncParams['modified']!=$localParams['modified'] &&
$syncParams['nonce']==$localParams['nonce']) {
$deltaModified = $syncParams['modified'] - $localParams['modified'];
if($deltaModified < -1 || $deltaModified > 1) {
$myLog->log(LOG_WARNING, 'We might have a replay. 2 events at different times have generated the same counters. The time difference is ' . $deltaModified . ' seconds');
}
}
if ($syncParams['nonce']!=$localParams['nonce']) {
$myLog->log(LOG_WARNING, 'Remote server has received a request to validate an already validated OTP ');
}
}
if ($localParams['active'] != 1) {
/* The remote server has accepted an OTP from a YubiKey which we would not.
* We still needed to update our counters with the counters from the OTP though.
*/
$myLog->log(LOG_WARNING, 'Received sync-request for de-activated Yubikey ' . $yk_publicname . ' - check database synchronization!!!');
2013-04-17 17:24:50 +02:00
sendResp(S_BAD_OTP, $myLog, $apiKey);
}
$extra = array(
2015-07-16 22:54:31 +02:00
'modified' => $localParams['modified'],
'nonce' => $localParams['nonce'],
'yk_publicname' => $yk_publicname,
'yk_counter' => $localParams['yk_counter'],
'yk_use' => $localParams['yk_use'],
'yk_high' => $localParams['yk_high'],
'yk_low' => $localParams['yk_low']
);
2013-04-17 17:24:50 +02:00
sendResp(S_OK, $myLog, $apiKey, $extra);