summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorb1galez <b1galez@fbcee277-3294-991b-8290-beb7048acdd6>2010-11-20 23:19:51 +0000
committerb1galez <b1galez@fbcee277-3294-991b-8290-beb7048acdd6>2010-11-20 23:19:51 +0000
commit06caccc4882ebdbb93ef0d4a0f6650e692d4443a (patch)
treecca3caa2618101bb674d51050682e6b2ef53a258
parentVersion 1.0 (diff)
downloadyubico-yubiserve-06caccc4882ebdbb93ef0d4a0f6650e692d4443a.tar.gz
yubico-yubiserve-06caccc4882ebdbb93ef0d4a0f6650e692d4443a.tar.bz2
yubico-yubiserve-06caccc4882ebdbb93ef0d4a0f6650e692d4443a.zip
Version 2.0
git-svn-id: http://yubico-yubiserve.googlecode.com/svn/trunk@4 fbcee277-3294-991b-8290-beb7048acdd6
-rw-r--r--README172
-rwxr-xr-xdbconf.py204
-rw-r--r--src/dump.sql30
-rw-r--r--yubikeys.sqlitebin5120 -> 11264 bytes
-rw-r--r--yubiserve-config.php28
-rw-r--r--yubiserve-utils.php80
-rw-r--r--yubiserve.php88
-rw-r--r--yubiserve.pngbin0 -> 25307 bytes
8 files changed, 364 insertions, 238 deletions
diff --git a/README b/README
index 860f23e..8b5d27f 100644
--- a/README
+++ b/README
@@ -1,39 +1,141 @@
-YubiServe has been written by Alessio Periloso <nospam *at* periloso.it>
+
+ == Author & Version ==
+YubiServe has been written by Alessio Periloso <mail *at* periloso.it>
Version 1.0: 21/05/2010
+Version 2.0: 19/11/2010
-This simple service allows to authenticate yubikeys using only a small
-sqlite database.
+ == Description ==
+This simple service allows to authenticate Yubikeys and OATH Tokens using
+only a small sqlite database.
The code has been released under GNU license (license into LICENSE file)
-To authenticate, call the script yubiserve.php with the parameter otp.
-Ex.: yubiserve.php?otp=vviblrbuicuvevcnnedbuuhjfhrebjlchhidkfrdkike
-
-To add a new key, run ./keyconf.py -a <publicname> <internalname> <aeskey>
-To delete a key, run ./keyconf.py -k <publicname>
-To disable a key (disabling a key won't delete it from the db), run
- ./keyconf.py -d <publicname>
-To enable a key, run ./keyconf.py -e <publicname>
-
-
-The YubiServe service needs the php-sqlite, php-mcrypt and python-sqlite support.
-On debian/ubuntu, you can run:
-sudo apt-get install php5-mcrypt php5-sqlite python-sqlite
-
-About Apache configuration, it is **REALLY IMPORTANT** users are not
-allowed to download the yubikeys.sqlite database. For this purpose,
-I wrote the .htaccess file into yubiserve directory. Sometimes
-however, into main Apache configuration the AllowOverride parameter
-is set to "None", and the .htaccess won't be loaded at all.
-If this is your case, be sure to add to your apache configuration the
-following lines (change <path to yubiserve>!!!):
-
- <Directory <path to yubiserve>/>
-#ex. <Directory /var/www/yubiserve/>
- Order deny,allow
- Deny from all
-
- <Files yubiserve.php>
- Order deny,allow
- Allow from all
- </Files>
- </Directory>
+The project is divided into two parts:
+ - The database management tool (dbconf.py)
+ - The validation server (yubiserve.py)
+
+
+ == The database management tool ==
+The database management tool helps you to manage keys in the database.
+For detailed help, run the database management tool with ./dbconf.py
+
+The tool allows you to add, delete, disable and enable keys/tokens.
+You can also add and remove API keys, to check the server signature in
+server responses.
+Everything is managed through nicknames, to make keys easy to remember
+who belong to.
+
+For example, to add a new yubikey, write:
+./dbconf.py -ya alessio vvkdtkjureru 980a8608b307 f1dc9c6585d600d06f9aae1abea2969e
+
+In this example, 'alessio' is the key nickname, 'vvkdtkjureru' is the
+key public identity (the one you can see at the beginning of your OTPs),
+'980a8608b307' is the private identity of the OTP (you can read it when
+you program your key), and the last parameter is the AES Key.
+
+
+To add a new OATH/HOTP:
+./dbconf.py -ha alessio 4rvn24642402 f03ddacdfebb6396f60d7045f41de68f5c5e1c3f
+
+In this other example, 'alessio' is still the nickname, '4rvn24642402' is
+the public identity of the token (it could be also 1, 2, 'alessio' or
+whatever you want; the Yubico implementation is 12 characters long)
+
+
+To add a new API key:
+./dbconf.py -aa alessio
+
+When you add a new API key, the configuration tool will return both
+the api key (ex. 'UkxFMnNFNTV4clRYUExSOWlONzQ=') and the API key id
+meant to be used later in your queries to the Yubiserve validation server.
+
+
+ == The Yubiserve Validation Server ==
+Understanding how to use the Yubiserve web application is pretty simple.
+You just have to run it (./yubiserve.py) and send your queries through
+HTTP GET connections.
+The default listening port is 8000, the default listening ip is 0.0.0.0
+(so you can connect to it from other machines). If you need it to answer
+only from local machine, you can change the ip to 127.0.0.1.
+When you connect to the server (ex. http://192.168.0.1:8000/), it will
+answer with a simple page, asking you Yubico Yubikeys OTPs or OATH/HOTP
+tokens.
+The Yubico Yubikey needs only one parameter: the OTP.
+The OATH/HOTP tokens needs two parameters: the OTP itself (6 or 8 digits)
+and the Token Identifier. The token identifier can be any character string
+you prefer, or, according to the standard OATH implementation, the preceding
+string to the OTP. The Yubico implementation follows this standard.
+The Yubiserve Validation Server, according to the standard, will try to
+find the Token Identifier preceding the OTP. If the string is found, the
+OTP will be verified according to that string; in case of LCD tokens,
+the string is not automatically added, so you will need to insert your ID
+in the second box to allow the Validation Server to find your own identity.
+
+
+ == Querying the Yubiserve Validation Server ==
+Querying the Yubiserve Validation Server is pretty simple.
+For Yubico Yubikeys, you will need to send a HTTP GET connection to:
+http://<server ip>:<server port>/wsapi/2.0/verify?otp=<your otp>
+ex.: http://192.168.0.1:8000/wsapi/2.0/verify?otp=vvnjbbkvjbcnhiretjvjfebbrdgrjjchdhtbderrdbhj
+This way you will try to authenticate to it, the simplest way possible.
+The response will be something like:
+
+otp=vvnjbbkvjbcnhiretjvjfebbrdgrjjchdhtbderrdbhj
+status=OK
+t=2010-11-20T23:54:35
+h=
+
+As you can see, the 'h' parameter is not set, and this is because we didn't use
+the signature through API Key. To use it, just add the 'key=<api key id>'
+parameter we had when we added the API Key.
+ex.: http://192.168.0.1:8000/wsapi/2.0/verify?otp=vvnjbbkvjbcnhiretjvjfebbrdgrjjchdhtbderrdbhj&id=1
+This time the response will be like:
+
+otp=vvnjbbkvjbcnhiretjvjfebbrdgrjjchdhtbderrdbhj
+status=OK
+t=2010-11-21T00:00:03
+h=6lrhQPKo1I/RQA1KPnjpuiOvVMc=
+
+To check the server signature, check the source code (you will have to do the
+exact same procedure to generate it and then just check if they are equal), or
+rely on the Yubico documentation on Validation Servers.
+
+For OATH/HOTP keys, the query can be simplified or not.
+If your token supports the 'Token Identifier', like Yubico Yubikeys, you can just
+send one parameter, the generated string, and the Yubiserve Validation Server will
+take care of looking for your key informations in the database.
+If your token instead only generates the 6-8 digits, you will have to explicit
+your publicID through another parameter.
+So, you will have to query, via HTTP GET, the following address:
+http://<server ip>:<server port>/wsapi/2.0/oathverify?otp=<your otp>&publicid=<token id>
+ex.: http://192.168.0.1:8000/wsapi/2.0/oathverify?otp=80l944311056173483
+ex.: ex.: http://192.168.0.1:8000/wsapi/2.0/oathverify?otp=173483&publicid=80l944311056
+Both the examples works the same way: in the first case, the Token Identifier was
+inside the generated OTP (like in Yubico Yubikey implementation), in the second case
+an authentication through a LCD Token was made, so the Yubiserve needed to know who
+the token belonged to, and the publicid parameter was added.
+The response, like Yubico Yubikey queries, is the following:
+
+otp=80l944311056173483
+status=OK
+t=2010-11-21T00:04:59
+h=
+
+The 'h' parameter is not set, because we didn't specified the API Key id. To use the
+server signature, we will need to add the 'id' parameter, like in the following query:
+ex.: http://192.168.1.2:8000/wsapi/2.0/oathverify?otp=80l944311056173483&id=1
+ex.: http://192.168.0.1:8000/wsapi/2.0/oathverify?otp=173483&publicid=80l944311056&id=1
+
+And this would be the the response:
+
+otp=80l944311056173483
+status=OK
+t=2010-11-21T00:10:56
+h=vYoG9Av8uG6OqVkmMFuANi4fyWw=
+
+
+ == Final thoughts ==
+
+That's all. Pretty simple, huh?
+Of course you can add new keys while the server is already running, without needing it
+to restart, and of course multiple queries a time are allowed, that's why the server
+is multithreaded. \ No newline at end of file
diff --git a/dbconf.py b/dbconf.py
new file mode 100755
index 0000000..894efde
--- /dev/null
+++ b/dbconf.py
@@ -0,0 +1,204 @@
+#!/usr/bin/python
+import sqlite, time, random, re
+from sys import argv
+
+def randomChars(max):
+ retVal = ''
+ for i in range(0, max):
+ rand = random.randrange(0, 63)
+ if (rand>36):
+ retVal += chr(rand-36+96) # Starting with 'a'
+ elif (rand>10):
+ retVal += chr(rand-10+64) # Starting with 'A'
+ else: # Starting with '0'
+ retVal += chr(rand+47)
+ return retVal
+
+con = sqlite.connect('yubikeys.sqlite')
+cur = con.cursor()
+
+if (len(argv)<2):
+ print ' == YubiServe Key Management Tool 2.0 ==\n'
+ print ' -ya <nickname> <publicid> <secretid> <aeskey>\tAdd a new Yubikey'
+ print ' -yk <nickname>\t\t\t\t\tDelete a Yubikey'
+ print ' -yd <nickname>\t\t\t\t\tDisable a Yubikey'
+ print ' -ye <nickname>\t\t\t\t\tEnable a Yubikey'
+ print ' -yl\t\t\t\t\t\tList all yubikeys in database\n'
+
+ print ' -ha <nickname> <publicid> <key>\t\tAdd a new OATH token'
+ print ' -hk <nickname>\t\t\t\t\tDelete a OATH token'
+ print ' -hd <nickname>\t\t\t\t\tDisable a OATH token'
+ print ' -he <nickname>\t\t\t\t\tEnable a OATH token'
+ print ' -hl\t\t\t\t\t\tList all OATH tokens in database\n'
+
+ print ' -aa <nickname>\t\t\t\t\tGenerate an API Key'
+ print ' -ak <nickname>\t\t\t\t\tRemove an API Key'
+ print ' -al\t\t\t\t\t\tList all API Keys in database\n'
+
+else:
+ if argv[1][0:2] == '-y': # Yubico Yubikey
+ if (argv[1][2] == 'd') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM yubikeys WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print 'Key not found.'
+ else:
+ cur.execute("SELECT * FROM yubikeys WHERE nickname = '" + nickname + "' AND active = 'true'")
+ if (cur.rowcount == 1):
+ cur.execute("UPDATE yubikeys SET active = 'false' WHERE nickname = '" + nickname + "'")
+ print "Key '" + nickname + "' disabled."
+ con.commit()
+ else:
+ print 'Key is already disabled.'
+
+ elif (argv[1][2] == 'e') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM yubikeys WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print 'Key not found.'
+ else:
+ cur.execute("SELECT * FROM yubikeys WHERE nickname = '" + nickname + "' AND active = 'false'")
+ if (cur.rowcount == 1):
+ cur.execute("UPDATE yubikeys SET active = 'true' WHERE nickname = '" + nickname + "'")
+ print "Key '" + nickname + "' enabled."
+ con.commit()
+ else:
+ print 'Key is already enabled.'
+ elif (argv[1][2] == 'k') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM yubikeys WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print 'Key not found.'
+ else:
+ cur.execute("DELETE FROM yubikeys WHERE nickname = '" + nickname + "'")
+ print "Key '" + nickname + "' deleted."
+ con.commit()
+ elif (argv[1][2] == 'a') and (len(argv)>4):
+ nickname = re.escape(argv[2])
+ if ((len(argv[2])<=16) and (len(argv[3]) <= 16) and (len(argv[4]) <= 12) and (len(argv[5])<=32)):
+ cur.execute("SELECT * FROM yubikeys WHERE nickname = '" + argv[2] + "' OR publicname = '" + argv[3] + "'")
+ if (cur.rowcount == 0):
+ cur.execute("INSERT INTO yubikeys VALUES ('" + argv[2] + "', '" + argv[3] + "', '" + time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) + "', '" + argv[4] + "', '" + argv[5] + "', 'true', 1, 1)")
+ con.commit()
+ print "Key '" + argv[2] + "' added to database."
+ else:
+ print 'Key is already into database. Delete it before adding the same key!'
+ else:
+ print 'Nickname and publicid must be max 16 characters long.'
+ print 'Secretid must be 12 characters max, aeskey must be 32 characters max.\n'
+ quit()
+ elif (argv[1][2] == 'l'):
+ cur.execute('SELECT nickname, publicname FROM yubikeys')
+ if cur.rowcount != 0:
+ print " " + str(cur.rowcount) + " keys into database:"
+ print '[Nickname]\t\t>> [PublicID]'
+ for i in range(0, cur.rowcount):
+ (nickname, publicname) = cur.fetchone()
+ print ' ' + nickname + ' ' * (23-len(nickname)) + ">> " + publicname
+ print ''
+ else:
+ print 'No keys in database\n'
+ else:
+ print 'Not enough parameters. Try looking at ' + argv[0] + ' --help'
+ elif argv[1][0:2] == '-h':
+ if (argv[1][2] == 'd') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM oathtokens WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print 'Key not found.'
+ else:
+ cur.execute("SELECT * FROM oathtokens WHERE nickname = '" + nickname + "' AND active = 'true'")
+ if (cur.rowcount == 1):
+ cur.execute("UPDATE oathtokens SET active = 'false' WHERE nickname = '" + nickname + "'")
+ print "Key '" + nickname + "' disabled."
+ con.commit()
+ else:
+ print 'Key is already disabled.'
+
+ elif (argv[1][2] == 'e') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM oathtokens WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print 'Key not found.'
+ else:
+ cur.execute("SELECT * FROM oathtokens WHERE nickname = '" + nickname + "' AND active = 'false'")
+ if (cur.rowcount == 1):
+ cur.execute("UPDATE oathtokens SET active = 'true' WHERE nickname = '" + nickname + "'")
+ print "Key '" + nickname + "' enabled."
+ con.commit()
+ else:
+ print 'Key is already enabled.'
+ elif (argv[1][2] == 'k') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM oathtokens WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print 'Key not found.'
+ else:
+ cur.execute("DELETE FROM oathtokens WHERE nickname = '" + nickname + "'")
+ print "Key '" + nickname + "' deleted."
+ con.commit()
+ elif (argv[1][2] == 'a') and (len(argv)>3):
+ nickname = re.escape(argv[2])
+ if (len(argv[2])<=16) and (len(argv[3]) <= 16) and (len(argv[4]) <= 40):
+ cur.execute("SELECT * FROM oathtokens WHERE nickname = '" + argv[2] + "' OR publicname = '" + argv[3] + "'")
+ if (cur.rowcount == 0):
+ cur.execute("INSERT INTO oathtokens VALUES ('" + nickname + "', '" + argv[3] + "', '" + time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) + "', '" + argv[4] + "', 'true', 1)")
+ con.commit()
+ print "Key '" + argv[2] + "' added to database."
+ else:
+ print 'Key is already into database. Delete it before adding the same key!'
+ else:
+ print 'Nickname and publicid must be max 16 characters long.'
+ print 'Secret key must be 40 characters max.\n'
+ quit()
+ elif (argv[1][2] == 'l'):
+ cur.execute('SELECT nickname, publicname FROM oathtokens')
+ if cur.rowcount != 0:
+ print " " + str(cur.rowcount) + " keys into database:"
+ print '[Nickname]\t\t>> [PublicID]'
+ for i in range(0, cur.rowcount):
+ (nickname, publicname) = cur.fetchone()
+ print ' ' + nickname + ' ' * (23-len(nickname)) + ">> " + publicname
+ print ''
+ else:
+ print 'No keys in database\n'
+ else:
+ print 'Not enough parameters. Try looking at ' + argv[0] + ' --help'
+ elif argv[1][0:2] == '-a':
+ if (argv[1][2] == 'a') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM apikeys WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount != 0):
+ print 'API Key for this nickname is already present. Remove it or choose another one.\n'
+ quit()
+ cur.execute('SELECT id FROM apikeys ORDER BY id DESC LIMIT 1')
+ if (cur.rowcount != 0):
+ id = cur.fetchone()[0] + 1
+ else:
+ id = 1
+ api_key = randomChars(20)
+ cur.execute("INSERT INTO apikeys VALUES ('" + nickname + "', '" + api_key + "', '" + str(id) + "')")
+ con.commit()
+ print "New API Key for '" + nickname + "': '" + api_key.encode('base64').strip() + "'"
+ print "Your API Key ID is: " + str(id) + "\n"
+ elif (argv[1][2] == 'k') and (len(argv)>2):
+ nickname = re.escape(argv[2])
+ cur.execute("SELECT * FROM apikeys WHERE nickname = '" + nickname + "'")
+ if (cur.rowcount == 0):
+ print "API Key for this nickname Doesn't exists!\n"
+ quit()
+ cur.execute("DELETE FROM apikeys WHERE nickname = '" + nickname + "'")
+ con.commit()
+ print "API Key for '" + nickname + "' has been deleted.\n"
+ elif (argv[1][2] == 'l'):
+ cur.execute('SELECT nickname FROM apikeys')
+ if cur.rowcount != 0:
+ print ' ' + str(cur.rowcount) + ' keys into database:'
+ print '[Nickname]'
+ for i in range(0, cur.rowcount):
+ nickname = cur.fetchone()[0]
+ print ' ' + nickname
+ print ''
+ else:
+ print 'No keys in database\n'
+ \ No newline at end of file
diff --git a/src/dump.sql b/src/dump.sql
index 859b68b..7cb972e 100644
--- a/src/dump.sql
+++ b/src/dump.sql
@@ -1,9 +1,25 @@
+BEGIN TRANSACTION;
create table yubikeys(
- publicname varchar(16) unique not null,
- created varchar(24) not null,
- internalname varchar(12) not null,
- aeskey varchar(32) not null,
- active boolean default true,
- counter integer not null default 1,
- time integer not null default 1
+ nickname varchar(16) unique not null,
+ publicname varchar(16) unique not null,
+ created varchar(24) not null,
+ internalname varchar(12) not null,
+ aeskey varchar(32) not null,
+ active boolean default true,
+ counter integer not null default 1,
+ time integer not null default 1
);
+create table oathtokens(
+ nickname varchar(16) unique not null,
+ publicname varchar(12) unique not null,
+ created varchar(24) not null,
+ secret varchar(40) not null,
+ active boolean default true,
+ counter integer not null default 1
+);
+create table apikeys(
+ nickname varchar(16),
+ secret varchar(28),
+ id integer primary key
+);
+COMMIT;
diff --git a/yubikeys.sqlite b/yubikeys.sqlite
index c42005b..0d4f75c 100644
--- a/yubikeys.sqlite
+++ b/yubikeys.sqlite
Binary files differ
diff --git a/yubiserve-config.php b/yubiserve-config.php
deleted file mode 100644
index b5654c2..0000000
--- a/yubiserve-config.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/*
-
-Written by Alessio Periloso <nospam *at* periloso.it>
-Version 1.0: 21/05/2010
-
-Licensed under GPL License (see LICENSE file)
-
-*/
-
-$filename = 'yubikeys.sqlite';
-
-
-
-if (!extension_loaded('mcrypt')) {
- die("mcrypt not loaded!");
-}
-
-$logfacility = LOG_LOCAL0;
-openlog("yubiserve", LOG_PID, $logfacility)
- or die("ERR Syslog open error\n");
-
-if (!($db = new SQLiteDatabase($filename))) {
- syslog(LOG_INFO, "Cannot access database");
- die("Cannot access database");
-}
-
-?>
diff --git a/yubiserve-utils.php b/yubiserve-utils.php
deleted file mode 100644
index 56669a6..0000000
--- a/yubiserve-utils.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/*
-YubiServe has been written by Alessio Periloso <nospam *at* periloso.it>
-
-
-This file is based on the work made by Simon Josefsson <simon@josefsson.org>.
-Follows his license:
-
-# Copyright (c) 2010 Yubico AB
-# 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.
-*/
-
-
-function hex2bin($h)
-{
- return pack("H*" , $h);
-}
-
-function modhex2hex($m)
-{
- return strtr($m, "cbdefghijklnrtuv", "0123456789abcdef");
-}
-
-function aes128ecb_decrypt($key,$in)
-{
- return bin2hex(mcrypt_ecb(MCRYPT_RIJNDAEL_128,
- hex2bin($key),
- hex2bin($in),
- MCRYPT_DECRYPT,
- hex2bin('00000000000000000000000000000000')));
-}
-
-function calculate_crc($token)
-{
- $crc = 0xffff;
-
- for ($i = 0; $i < 16; $i++ ) {
- $b = hexdec($token[$i*2].$token[($i*2)+1]);
- $crc = $crc ^ ($b & 0xff);
- for ($j = 0; $j < 8; $j++) {
- $n = $crc & 1;
- $crc = $crc >> 1;
- if ($n != 0) {
- $crc = $crc ^ 0x8408;
- }
- }
- }
- return $crc;
-}
-
-function crc_is_good($token) {
- $crc = calculate_crc($token);
- return $crc == 0xf0b8;
-}
-
-?>
diff --git a/yubiserve.php b/yubiserve.php
deleted file mode 100644
index 946a8fa..0000000
--- a/yubiserve.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?
-/*
-
-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($plaintext, 0, 12);
-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($plaintext, 14, 2) . substr($plaintext, 12, 2);
-$low = substr($plaintext, 18, 2) . substr($plaintext, 16, 2);
-$high = substr($plaintext, 20, 2);
-$use = substr($plaintext, 22, 2);
-
-$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);
-?>
diff --git a/yubiserve.png b/yubiserve.png
new file mode 100644
index 0000000..ce4c31c
--- /dev/null
+++ b/yubiserve.png
Binary files differ