summaryrefslogtreecommitdiff
path: root/yubiserve.php
blob: 946a8faba6b5caf7f9f95316be707ef9aed7dc51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<?
/*
 
Written by Alessio Periloso <nospam *at* periloso.it>
Version 1.0: 21/05/2010
 
Licensed under GPL License (see LICENSE file)
 
*/
 
require_once 'yubiserve-config.php';
require_once 'yubiserve-utils.php';
 
if (!isset($_REQUEST["otp"]))
  die ("ERR Missing OTP\n");
$otp = trim($_REQUEST["otp"]);
 
if ((strlen($otp)<32|| (strlen($otp)>48)) {
  syslog(LOG_INFO"Malformed OTP: $otp");
  die ("ERR Malformed OTP\n");
}
 
if (!preg_match("/^([cbdefghijklnrtuv]{0,16})([cbdefghijklnrtuv]{32})$/"$otp$matches)) {
  syslog(LOG_INFO"Invalid OTP format: $otp");
  die("ERR Invalid OTP format\n");
 }
 
$id = $matches[1];
$modhex_ciphertext = $matches[2];
 
$results = @$db->query("SELECT aeskey, internalname FROM yubikeys WHERE publicname = '$id' AND active = 'true'");
if ($results === false{
  syslog(LOG_INFO"Unknown yubikey (internalname: $id)");
  die("ERR Unknown yubikey\n");
}
 
$row = $results->fetchAll(SQLITE_ASSOC);
if (count($row)>1{
  syslog(LOG_INFO"Multiple keys returned! OTP: $otp");
  die("ERR Malformed OTP");
} elseif (count($row)<1{
  syslog(LOG_INFO"Unknown yubikey (internalname: $id)");
  die("ERR Unknown yubikey\n");
}
 
$aeskey = $row[0]['aeskey'];
$internalname = $row[0]['internalname'];
 
$ciphertext = modhex2hex($modhex_ciphertext);
$plaintext = aes128ecb_decrypt($aeskey$ciphertext);
 
$uid = substr($plaintext012);
if (strcmp($uid$internalname!= 0{
  syslog(LOG_ERR"UID error: $otp $plaintext$uid vs $internalname");
  die("ERR Corrupt OTP\n");
}
 
if (!crc_is_good($plaintext)) {
  syslog(LOG_ERR"CRC error: $otp$plaintext");
  die("ERR Corrupt OTP\n");
}
 
$counter = substr($plaintext142. substr($plaintext122);
$low = substr($plaintext182. substr($plaintext162);
$high = substr($plaintext202);
$use = substr($plaintext222);
 
$timestamp = hexdec($high . $low);
$internalcounter = hexdec($counter . $use);
 
#print("$counter $use $high $low\n"); 
 
$results = @$db->query("SELECT counter, time FROM yubikeys WHERE publicname = '$id' AND active = 'true' AND counter < $internalcounter");
$row = @$results->fetchAll(SQLITE_ASSOC);
 
if (count($row)!=1{
  syslog(LOG_ERR"REPLAYED OTP for yubikey $id (same counter)");
  die("ERR Replayed OTP");
} elseif ((($row[0] >> 8== ($internalcounter >> 8)) && ($row[1] <= $timestamp)) {
  syslog(LOG_ERR"REPLAYED OTP for yubikey $id (same timestamp)");
  die("ERR Replayed OTP");
}
 
print "OK Authentication success";
$results = $db->query("UPDATE yubikeys SET counter = $internalcounter, time = $timestamp WHERE publicname = '$id'");
 
unset($db);
?>