$value){ $str .= "$key=$value "; } } else { $str .= $msg . " "; } } error_log($str); } // Return eg. 2008-11-21T06:11:55Z0711 // function getUTCTimeStamp() { date_default_timezone_set('UTC'); $tiny = substr(microtime(false), 2, 3); return date('Y-m-d\TH:i:s\Z0', time()) . $tiny; } // Sign a http query string in the array of key-value pairs // return b64 encoded hmac hash function sign($a, $apiKey) { ksort($a); $qs = ''; $n = count($a); $i = 0; foreach (array_keys($a) as $key) { $qs .= trim($key).'='.trim($a[$key]); 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); debug('SIGN: ' . $qs . ' H=' . $hmac); return $hmac; } // sign an array of query string function hex2b64 ($hex_str) { $bin = pack("H*", $hex_str); return base64_encode($bin); } function modhex2b64 ($modhex_str) { $hex_str = strtr ($modhex_str, "cbdefghijklnrtuv", "0123456789abcdef"); return hex2b64($hex_str); } // 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 ^OK is returned, // or if all URLs failed, false. function retrieveURLasync ($urls) { $mh = curl_multi_init(); $ch = array(); foreach ($urls as $id => $url) { $handle = curl_init(); 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; 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']); if (preg_match("/^OK/", $str)) { $error = curl_error ($info['handle']); $errno = curl_errno ($info['handle']); $info = curl_getinfo ($info['handle']); debug("YK-KSM errno/error: " . $errno . "/" . $error, $info); foreach ($ch as $h) { curl_multi_remove_handle ($mh, $h); curl_close ($h); } curl_multi_close ($mh); return $str; } 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; } // $otp: A yubikey OTP function KSMdecryptOTP($urls) { $ret = array(); $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 // $devId: The first 12 chars from the OTP function getAuthData($conn, $devId) { $tokenId = modhex2b64($devId); $stmt = 'SELECT id, active, client_id, counter, sessionUse, low, high, accessed '. 'FROM yubikeys '. 'WHERE tokenId='.mysql_quote($tokenId); $r = query($conn, $stmt); if (mysql_num_rows($r) > 0) { $row = mysql_fetch_assoc($r); mysql_free_result($r); return $row; } return null; } // End getAuthData function addNewKey($conn, $devId) { $tokenId = modhex2b64($devId); $stmt = 'INSERT INTO yubikeys (client_id, active, created, tokenId, counter) '. 'VALUES (1, true, NOW(), ' . mysql_quote($tokenId) . ', 0)'; $r = query($conn, $stmt); } // $clientId: The decimal client identity function getClientData($conn, $clientId) { $stmt = 'SELECT id, secret '. 'FROM clients '. 'WHERE active AND id='.mysql_quote($clientId); $r = query($conn, $stmt); if (mysql_num_rows($r) > 0) { $row = mysql_fetch_assoc($r); mysql_free_result($r); return $row; } return null; } // End getClientData ?>