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

252 lines
6.4 KiB
PHP
Raw Normal View History

2008-09-26 05:21:11 +02:00
<?php
2009-03-11 02:42:23 +01:00
require_once('ykval-log.php');
2008-09-26 05:21:11 +02:00
define('S_OK', 'OK');
define('S_BAD_OTP', 'BAD_OTP');
define('S_REPLAYED_OTP', 'REPLAYED_OTP');
2009-03-11 01:19:59 +01:00
define('S_DELAYED_OTP', 'DELAYED_OTP');
2008-09-26 05:21:11 +02:00
define('S_BAD_SIGNATURE', 'BAD_SIGNATURE');
define('S_MISSING_PARAMETER', 'MISSING_PARAMETER');
2009-03-10 23:01:46 +01:00
define('S_NO_SUCH_CLIENT', 'NO_SUCH_CLIENT');
2008-09-26 05:21:11 +02:00
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');
2009-03-11 02:42:23 +01:00
define('TS_SEC', 1/8);
define('TS_REL_TOLERANCE', 0.3);
define('TS_ABS_TOLERANCE', 20);
2008-09-26 05:21:11 +02:00
2009-03-18 12:00:48 +01:00
define('TOKEN_LEN', 32);
2009-03-10 23:50:35 +01:00
global $ykval_common_log;
$ykval_common_log = new Log('ykval-common');
function logdie ($str)
{
global $ykval_common_log;
2010-02-22 14:17:52 +01:00
$ykval_common_log->log(LOG_INFO, $str);
die($str . "\n");
}
2009-03-10 23:50:35 +01:00
function unescape($s) {
return str_replace('\\', "", $s);
}
function getHttpVal($key, $defaultVal) {
$val = $defaultVal;
if (array_key_exists($key, $_GET)) {
$val = $_GET[$key];
} else if (array_key_exists($key, $_POST)) {
$val = $_POST[$key];
}
$v = unescape(trim($val));
return $v;
}
function debug() {
$str = "";
foreach (func_get_args() as $msg)
{
if (is_array($msg)) {
foreach($msg as $key => $value){
$str .= "$key=$value ";
}
} else {
$str .= $msg . " ";
}
2009-03-11 01:54:19 +01:00
}
global $ykval_common_log;
$ykval_common_log->log(LOG_DEBUG, $str);
2008-09-26 05:21:11 +02:00
}
// Return eg. 2008-11-21T06:11:55Z0711
2008-11-21 07:41:13 +01:00
//
2008-09-27 11:04:49 +02:00
function getUTCTimeStamp() {
date_default_timezone_set('UTC');
$tiny = substr(microtime(false), 2, 3);
return date('Y-m-d\TH:i:s\Z0', time()) . $tiny;
2008-09-27 11:04:49 +02:00
}
# NOTE: When we evolve to using general DB-interface, this functinality
# should be moved there.
function DbTimeToUnix($db_time)
{
$unix=strptime($db_time, '%F %H:%M:%S');
return mktime($unix[tm_hour], $unix[tm_min], $unix[tm_sec], $unix[tm_mon]+1, $unix[tm_mday], $unix[tm_year]+1900);
}
function UnixToDbTime($unix)
{
return date('Y-m-d H:i:s', $unix);
}
2008-09-27 11:04:49 +02:00
// Sign a http query string in the array of key-value pairs
// return b64 encoded hmac hash
2009-03-11 03:06:02 +01:00
function sign($a, $apiKey) {
2008-09-27 11:04:49 +02:00
ksort($a);
$qs = '';
$n = count($a);
$i = 0;
foreach (array_keys($a) as $key) {
2008-11-21 22:41:26 +01:00
$qs .= trim($key).'='.trim($a[$key]);
2008-09-27 11:04:49 +02:00
if (++$i < $n) {
$qs .= '&';
}
}
// the TRUE at the end states we want the raw value, not hexadecimal form
$hmac = hash_hmac('sha1', utf8_encode($qs), $apiKey, true);
$hmac = base64_encode($hmac);
2009-03-11 02:53:38 +01:00
debug('SIGN: ' . $qs . ' H=' . $hmac);
2008-09-27 11:04:49 +02:00
return $hmac;
2008-10-08 08:29:19 +02:00
} // sign an array of query string
2008-09-27 11:04:49 +02:00
function hex2b64 ($hex_str) {
$bin = pack("H*", $hex_str);
return base64_encode($bin);
2009-03-10 23:50:35 +01:00
}
function modhex2b64 ($modhex_str) {
$hex_str = strtr ($modhex_str, "cbdefghijklnrtuv", "0123456789abcdef");
return hex2b64($hex_str);
2009-03-10 23:50:35 +01:00
}
// This function takes a list of URLs. It will return the content of
// the first successfully retrieved URL, whose content matches ^OK.
// The request are sent asynchronously. Some of the URLs can fail
// with unknown host, connection errors, or network timeout, but as
// long as one of the URLs given work, data will be returned. If all
// URLs fail, data from some URL that did not match parameter $match
// (defaults to ^OK) is returned, or if all URLs failed, false.
function retrieveURLasync ($urls, $ans_req=1, $match="^OK", $returl=False) {
$mh = curl_multi_init();
$ch = array();
foreach ($urls as $id => $url) {
$handle = curl_init();
debug("url is: " . $url);
curl_setopt($handle, CURLOPT_URL, $url);
curl_setopt($handle, CURLOPT_USERAGENT, "YK-VAL");
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($handle, CURLOPT_FAILONERROR, true);
curl_setopt($handle, CURLOPT_TIMEOUT, 10);
curl_multi_add_handle($mh, $handle);
$ch[$handle] = $handle;
}
$str = false;
$ans_count = 0;
$ans_arr = array();
do {
while (($mrc = curl_multi_exec($mh, $active)) == CURLM_CALL_MULTI_PERFORM)
;
while ($info = curl_multi_info_read($mh)) {
debug ("YK-KSM multi", $info);
if ($info['result'] == CURL_OK) {
$str = curl_multi_getcontent($info['handle']);
debug($str);
if (preg_match("/".$match."/", $str)) {
$error = curl_error ($info['handle']);
$errno = curl_errno ($info['handle']);
$cinfo = curl_getinfo ($info['handle']);
debug("YK-KSM errno/error: " . $errno . "/" . $error, $cinfo);
$ans_count++;
debug("found entry");
if ($returl) $ans_arr[]="url=" . $cinfo['url'] . "\n" . $str;
else $ans_arr[]=$str;
}
if ($ans_count >= $ans_req) {
foreach ($ch as $h) {
curl_multi_remove_handle ($mh, $h);
curl_close ($h);
}
curl_multi_close ($mh);
if ($ans_count==1) return $ans_arr[0];
else return $ans_arr;
}
curl_multi_remove_handle ($mh, $info['handle']);
curl_close ($info['handle']);
unset ($ch[$info['handle']]);
}
curl_multi_select ($mh);
}
} while($active);
foreach ($ch as $h) {
curl_multi_remove_handle ($mh, $h);
curl_close ($h);
}
curl_multi_close ($mh);
return $str;
}
function retrieveURLsimple ($url, $match="^OK") {
foreach (file($url) as $line) {
if (preg_match("/".$match."/", $line)) {
return $line;
}
}
return false;
}
// $otp: A yubikey OTP
function KSMdecryptOTP($urls) {
$ret = array();
if (!is_array($urls)) {
$response = retrieveURLsimple ($urls);
} elseif (count($urls) == 1) {
$response = retrieveURLsimple ($urls[0]);
} else {
$response = retrieveURLasync ($urls);
}
if ($response) {
debug("YK-KSM response: " . $response);
}
if (sscanf ($response,
"OK counter=%04x low=%04x high=%02x use=%02x",
$ret["session_counter"], $ret["low"], $ret["high"],
$ret["session_use"]) != 4) {
return false;
}
return $ret;
} // End decryptOTP
2009-03-10 23:50:35 +01:00
function sendResp($status, $apiKey = '', $extra = null) {
2009-05-06 17:07:05 +02:00
if ($status == null) {
$status = S_BACKEND_ERROR;
}
$a['status'] = $status;
$a['t'] = getUTCTimeStamp();
if ($extra){
foreach ($extra as $param => $value) $a[$param] = $value;
}
2009-05-06 17:07:05 +02:00
$h = sign($a, $apiKey);
echo "h=" . $h . "\r\n";
echo "t=" . ($a['t']) . "\r\n";
if ($extra){
foreach ($extra as $param => $value) {
echo $param . "=" . $value . "\r\n";
}
}
2009-05-06 17:07:05 +02:00
echo "status=" . ($a['status']) . "\r\n";
echo "\r\n";
}
2008-09-26 05:21:11 +02:00
?>