mirror of
https://github.com/Yubico/yubikey-val.git
synced 2025-02-01 10:52:18 +01:00
removed submodule
This commit is contained in:
parent
79ce2eb646
commit
7dc8fdc9f7
1
doc
1
doc
@ -1 +0,0 @@
|
||||
Subproject commit b0b6a75ec10e353551b88f5c89ec948ecfaee581
|
37
doc/ClientInfoFormat.adoc
Normal file
37
doc/ClientInfoFormat.adoc
Normal file
@ -0,0 +1,37 @@
|
||||
=Format of Client Info Data=
|
||||
|
||||
This file holds data used in the YubiKey OTP validation phase.
|
||||
|
||||
Each of the lines in the file follows the following format:
|
||||
|
||||
```
|
||||
id,active,created,secret,email,notes,otp
|
||||
```
|
||||
|
||||
Any empty line, or a line beginning with a # is ignored.
|
||||
|
||||
The meaning are as follows:
|
||||
|
||||
;id:
|
||||
: the client identity, decimal integer
|
||||
;active
|
||||
: the client state, 1 if active, 0 if not
|
||||
;created
|
||||
: unix timestamp of when the client was created, decimal integer
|
||||
;secret
|
||||
: printable ascii string with shared HMAC secret for client id
|
||||
;email
|
||||
: the email address used by the client, printable ascii string
|
||||
;notes
|
||||
: not used, printable ascii string
|
||||
;otp
|
||||
: the YubiKey OTP used to create the client, modhex string
|
||||
|
||||
An examples of a valid data line:
|
||||
|
||||
```
|
||||
1,1,1359550387,foobar,user@example.com,,cccccccccccbubfncnklbknnkrfvfkbubftlfliikdrt
|
||||
```
|
||||
|
||||
For an example of importing and exporting Client Info data, please see
|
||||
[[ImportExportData|Importing and Exporting Data]].
|
61
doc/GeneratingClients.adoc
Normal file
61
doc/GeneratingClients.adoc
Normal file
@ -0,0 +1,61 @@
|
||||
= Generating Clients =
|
||||
|
||||
For a client to be able to authenticate a YubiKey OTP with the Validation
|
||||
service, a client ID and matching secret is needed (the secret is only
|
||||
required for authenticated verification). To create a new client in the
|
||||
database with a new generated secret, the ykval-gen-clients command can be
|
||||
used. This document describes step by step instructions on generating and
|
||||
using clients. For more information regarding the various fields of the
|
||||
client database, see [[ClientInfoFormat|Client Info Format]].
|
||||
|
||||
== Client generation ==
|
||||
Use the command below to generate 5 clients. Note the usage of the --urandom
|
||||
flag, which speeds up generation, but is less secure! The command is run
|
||||
as root (using sudo), since it needs to be able to read the database
|
||||
configuration stored in /etc/yubico/val/config-db.php.
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo ykval-gen-clients --urandom 5
|
||||
|
||||
1,l+/c/XfDPDHsaNKrpjwL+bf/Hgs=
|
||||
2,LPGHqukoIAUGgDuOs7O0e1f8xD0=
|
||||
3,K+gWRE0euOjVOiLD4Nm0wyHrHY8=
|
||||
4,+8LF+ADANTAHnwB82xkBb+mNEFs=
|
||||
5,URc6oabcuRV8OWW1Hs1cYym3ba4=
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
== Testing the clients ==
|
||||
The above clients can now be used with the validation server. If you have
|
||||
a YubiKey validation client, you can easily test this now. For example,
|
||||
using the ykclient command (available in the ykclient-dev package, which is
|
||||
in Debian as well as Ubuntu):
|
||||
|
||||
```sh
|
||||
user@val:~$ ykclient --url "http://127.0.0.1/wsapi/2.0/verify?id=%d&otp=%s" --apikey LPGHqukoIAUGgDuOs7O0e1f8xD0= 2 cccccccccccdutfiljtbignbgckhgdtfigbdricugdrv
|
||||
Input:
|
||||
validation URL: http://127.0.0.1/wsapi/2.0/verify?id=%d&otp=%s
|
||||
client id: 2
|
||||
token: cccccccccccdutfiljtbignbgckhgdtfigbdricugdrv
|
||||
api key: LPGHqukoIAUGgDuOs7O0e1f8xD0=
|
||||
Verification output (1): Yubikey OTP was bad (BAD_OTP)
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
Note that even though the response was BAD_OTP (since the key used is in fact
|
||||
a bad OTP), the verification worked as expected. Compare it to the next example:
|
||||
|
||||
```sh
|
||||
user@val:~$ ykclient --url "http://127.0.0.1/wsapi/2.0/verify?id=%d&otp=%s" --apikey not_a_real_secret 3 cccccccccccdutfiljtbignggckhgdtfigbdricugdrvInput:
|
||||
validation URL: http://127.0.0.1/wsapi/2.0/verify?id=%d&otp=%s
|
||||
client id: 3
|
||||
token: cccccccccccdutfiljtbignggckhgdtfigbdricugdrv
|
||||
api key: not_a_real_secret
|
||||
Verification output (106): Server response signature was invalid (BAD_SERVER_SIGNATURE)
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
In the above example, the server actually noticed that the client secret was
|
||||
incorrect, and responded as it should. The response is signed with the correct
|
||||
secret, which the client then interprets as invalid (since it thinks the
|
||||
correct key is the dummy key we just gave it).
|
137
doc/GettingStartedWritingClients.adoc
Normal file
137
doc/GettingStartedWritingClients.adoc
Normal file
@ -0,0 +1,137 @@
|
||||
Getting Started Writing Clients
|
||||
===============================
|
||||
|
||||
## Introduction
|
||||
|
||||
While the canonical description of the validation protocol is
|
||||
documented in link:ValidationProtocolV20[ValidationProtocolV20], it may be difficult to grasp the
|
||||
high level of how a client typically works. The intention with this
|
||||
page is to illustrate one simple case. Note that this does not cover
|
||||
the replicated protocol.
|
||||
|
||||
If you want to make your own client implementation, here is the
|
||||
quickest way to get started:
|
||||
|
||||
## API key
|
||||
|
||||
API key is used to optionally sign the OTP validation request and to
|
||||
verify the OTP validation response. We recommend all production
|
||||
deployments use either API key or HTTPS.
|
||||
|
||||
If you use HTTPS to access Yubico's validation web service and you
|
||||
validate the Yubico server SSL certificate, you don't need to use the
|
||||
shared key to further authenticate response signatures from Yubico.
|
||||
|
||||
If you for some reason do not want to rely on HTTPS. You may also sign
|
||||
requests using this API key.
|
||||
|
||||
To get an API key, first use our online API key generator. It will
|
||||
assign you an ID and create a shared key. You can use the shared key
|
||||
to authenticate that the API responses do come from Yubico.
|
||||
|
||||
## Capture an OTP
|
||||
|
||||
Capture an OTP output from your YubiKey. You can do that by opening
|
||||
a text editor and simply pressing the button on the YubiKey. The OTP is a
|
||||
simple string of characters, like this:
|
||||
|
||||
```
|
||||
vvvvvvcurikvhjcvnlnbecbkubjvuittbifhndhn
|
||||
```
|
||||
|
||||
## Validate OTP format
|
||||
|
||||
Prudent clients should validate the data entered by the user so that
|
||||
it is what the software expects. YubiKey OTPs consists of 32-48
|
||||
characters in the ModHex alphabet `cbdefghijklnrtuv`. Unfortunately,
|
||||
this has turned to be over-aggresive because if the keyboard layout is
|
||||
Dvorak-based, it will look differently. For example, the modhex
|
||||
alphabet in the US Dvorak layout is `jxe.uidchtnbpygk`. There are
|
||||
other Dvorak layouts as well. For this reason, our recommendation is
|
||||
that clients only check that the input consists of 32-48 printable
|
||||
characters.
|
||||
|
||||
## Send OTP to our server
|
||||
|
||||
Send the authentication request to our servers following the protocol
|
||||
specified below. Your request should include the verifier ID (a number
|
||||
that identifies the signature key), the OTP you captured in the
|
||||
previous instruction, and a random looking string of characters to
|
||||
make the request unique. The request is part of the HTTP GET URL,
|
||||
encoded using normal parameter/value pairs. For example (broken into
|
||||
two lines for legibility):
|
||||
|
||||
```
|
||||
http://api2.yubico.com/wsapi/2.0/verify?id=1&otp=cccccccbcjdifc\
|
||||
trndncchkftchjlnbhvhtugdljibej&nonce=aef3a7835277a28da831005c2ae3b919e2076a62
|
||||
```
|
||||
|
||||
The servers that we provide are:
|
||||
|
||||
```
|
||||
api.yubico.com
|
||||
api2.yubico.com
|
||||
api3.yubico.com
|
||||
api4.yubico.com
|
||||
api5.yubico.com
|
||||
```
|
||||
|
||||
These servers are hosted in different places and by different organizations.
|
||||
|
||||
## Parse response
|
||||
|
||||
You will recieve a response back from the server, a string of text
|
||||
that resembles the following:
|
||||
|
||||
```
|
||||
h=vjhFxZrNHB5CjI6vhuSeF2n46a8=
|
||||
t=2010-04-23T20:34:51Z0678
|
||||
otp=cccccccbcjdifctrndncchkftchjlnbhvhtugdljibej
|
||||
nonce=aef3a7835277a28da831005c2ae3b919e2076a62
|
||||
sl=75
|
||||
status=OK
|
||||
```
|
||||
|
||||
You can check the authenticity of this response by checking that the
|
||||
OTP and nonce was the same as the one you requested validation for and
|
||||
verify the HMAC-SHA-1 signature.
|
||||
|
||||
## Make a decision
|
||||
|
||||
Use the `status=` codes to make a decision whether to authenticate
|
||||
your user or not. All the status codes and their meanings are
|
||||
described by the protocol specification, see below.
|
||||
|
||||
## Binding an OTP to an Identity
|
||||
|
||||
Since a valid OTP on its own is not terribly useful, you need to
|
||||
connect it to a user in some way. This is normally not something the
|
||||
client needs to do, it belongs elsewhere in the application, however
|
||||
for completeness we mention how it is done here.
|
||||
|
||||
In some situations, the user is typing her username directly into your
|
||||
application, which solves the issue.
|
||||
|
||||
More generally, the YubiKey OTP contains as the initial part an
|
||||
identity of the YubiKey, and it can be used to identify the user. The
|
||||
identity part is the same for every OTP, and it is the initial 2-16
|
||||
modhex characters of the OTP. (The identity can be programmed to 0
|
||||
characters, but then obviously this scheme does not apply.) Since the
|
||||
rest of the OTP is always 32 characters, the method to extract the
|
||||
identity is to remove 32 characters from the end and then use the
|
||||
remaining string, which should be 2-16 characters, as the YubiKey
|
||||
identity.
|
||||
|
||||
Note that the validation server is case insensitive, so you need to
|
||||
lower-case the string in order to avoid caps lock resulting in
|
||||
different identities with the only differ being case of the prefix.
|
||||
|
||||
Typically you would store the association between the user and the
|
||||
YubiKey prefix in a database.
|
||||
|
||||
## The End
|
||||
|
||||
There are some more subtle matters that can be important, so please
|
||||
read the entire protocol specification for all the details. Further,
|
||||
for added reliability, you may send the request in parallel to more
|
||||
than one server, which is not explained above.
|
80
doc/ImportExportData.adoc
Normal file
80
doc/ImportExportData.adoc
Normal file
@ -0,0 +1,80 @@
|
||||
= Importing and Exporting Data =
|
||||
|
||||
The yubikey-val database holds client data as well as yubikey counter data
|
||||
which you can import and export using the provided tools. As it is important
|
||||
to protect the data, we will show you how to encrypt and decrypt these files
|
||||
using GnuPG. You will therefor require a private key for both importing as
|
||||
well as exporting (these can be the same keys, or differnent ones, depending
|
||||
on if you are importing on the same system as you have exported from).
|
||||
|
||||
== Client Info Data ==
|
||||
|
||||
The client data holds information about the clients that are able to use the
|
||||
validation service, such as their ID and secret key. This data is stored in
|
||||
the *clients* table of the database.
|
||||
|
||||
The infomation here covers exporting existing clients to a file, and importing
|
||||
the clients from that file into another database. For generating clients, see
|
||||
[[GeneratingClients|Generating Clients]].
|
||||
|
||||
To export client data, you can use the following command (Replace C5B8D4EA with
|
||||
the key of the recipient of the data):
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo ykval-export-clients | gpg -a --encrypt -r C5B8D4EA -s > yk-client-info.asc
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "YK-KSM import key"
|
||||
2048-bit RSA key, ID C5B8D4EA, created 2013-01-28
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
To import the client data exported above, you can use:
|
||||
```sh
|
||||
user@val:~$ gpg < yk-client-info.asc | sudo ykval-import-clients
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "YK-KSM import key"
|
||||
2048-bit RSA key, ID 9372DC00, created 2013-01-28 (main key ID C5B8D4EA)
|
||||
|
||||
gpg: encrypted with 2048-bit RSA key, ID 9372DC00, created 2013-01-28
|
||||
"YK-KSM import key"
|
||||
gpg: Signature made Tue 29 Jan 2013 04:18:21 PM CET using RSA key ID C5B8D4EA
|
||||
gpg: Good signature from "YK-KSM import key"
|
||||
Successfully imported clients to database
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
== Yubikey Counter Data ==
|
||||
|
||||
The Yubikey counter data holds information about the state of the known
|
||||
Yubikeys, such as their various counter values. This data is stored in the
|
||||
*yubikeys* table of the database.
|
||||
|
||||
To export Yubikey counter data, you can use the following command (Replace
|
||||
C5B8D4EA with the key of the recipient of the data):
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo ykval-export | gpg -a --encrypt -r C5B8D4EA -s > yk-counter-data.asc
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "YK-KSM import key"
|
||||
2048-bit RSA key, ID C5B8D4EA, created 2013-01-28
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
To import the counter data exported above, you can use:
|
||||
```sh
|
||||
user@val:~$ gpg < yk-counter-data.asc | sudo ykval-import
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "YK-KSM import key"
|
||||
2048-bit RSA key, ID 9372DC00, created 2013-01-28 (main key ID C5B8D4EA)
|
||||
|
||||
gpg: encrypted with 2048-bit RSA key, ID 9372DC00, created 2013-01-28
|
||||
"YK-KSM import key"
|
||||
gpg: Signature made Tue 29 Jan 2013 04:18:21 PM CET using RSA key ID C5B8D4EA
|
||||
gpg: Good signature from "YK-KSM import key"
|
||||
Successfully imported yubikeys to database
|
||||
user@val:~$
|
||||
```
|
586
doc/Installation.adoc
Normal file
586
doc/Installation.adoc
Normal file
@ -0,0 +1,586 @@
|
||||
== Introduction ==
|
||||
|
||||
This document describes how to get one instance of the Yubikey
|
||||
Validation Server (YK-VAL) up and running.
|
||||
|
||||
The purpose of the Yubikey validation server is to validate Yubikey
|
||||
OTPs. The validation server is written in PHP, and thus needs a web
|
||||
server and a database. We will use Apache and MySQL, but with small
|
||||
modifications it should be possible to use with other implementations
|
||||
too (e.g., lighttpd and PostgreSQL).
|
||||
|
||||
The validation server needs to talk to a Yubikey Key Storage Module
|
||||
(YK-KSM) to work. Thus, you either need to arrange for access to a
|
||||
remote YK-KSM and get the URL to it, or install your own YK-KSM.
|
||||
|
||||
Currently there are two recommended implementations of a YK-KSM. If you have a YubiHSM hardware dongle and want improve security, we recommend using Python-PyHSM:
|
||||
|
||||
[https://github.com/Yubico/python-pyhsm]
|
||||
|
||||
Otherwise we recommend the "soft" YK-KSM:
|
||||
|
||||
[https://github.com/Yubico/yubikey-ksm/]
|
||||
|
||||
The YK-KSM can be on the same machine as the validation server, but
|
||||
for improved security we recommend to use different machines for the
|
||||
validation server and the KSM.
|
||||
|
||||
The OTP validation service is delivered through web service API.
|
||||
There's no web-based HTML form interface involved. The protocol is
|
||||
defined at:
|
||||
|
||||
[http://www.yubico.com/developers/api/]
|
||||
|
||||
For redundancy it is possible to set up multiple instances of the
|
||||
YubiKey Validation Server. The intent is that clients should be able
|
||||
to continue validate OTPs even if one of the servers are down. This
|
||||
is reflected in the configuration of a YK-VAL by having a "sync pool"
|
||||
concept. The sync pool of a particular YK-VAL instance is a list of
|
||||
URLs that the local server will synchronize the OTP with, depending on
|
||||
client request. Normally if you have 5 servers, each server will have
|
||||
a list of the 4 other servers in its sync pool -- however it IS
|
||||
possible to deviate from this if for some reason it is not possible to
|
||||
reach one particular server from one of the servers. For simplicity,
|
||||
we strongly recommend you to list non-local servers in each sync pool
|
||||
though.
|
||||
|
||||
== Installation ==
|
||||
|
||||
This following steps applies to any GNU/Linux-like system, although it
|
||||
was written for Debian GNU/Linux. If you do not know which OS to use,
|
||||
we recommend a default choice of Ubuntu 12.04 LTS since it is a
|
||||
well-known distribution that comes with 5 years of security support.
|
||||
Install the OS following its manual and enable automatic security
|
||||
upgrades if prompted.
|
||||
|
||||
=== Step 1: YK-VAL Installation ===
|
||||
|
||||
First you should download and install the latest YK-VAL release:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo apt-get install git make
|
||||
...
|
||||
user@val:~$ git clone git://github.com/Yubico/yubikey-val.git
|
||||
...
|
||||
user@val:~$ cd yubikey-val
|
||||
user@val:~/yubikey-val$ sudo make install
|
||||
```
|
||||
|
||||
The rest of this documentation will assume you have YK-VAL available
|
||||
in the default installation targets. You can override the paths, see
|
||||
the Makefile.
|
||||
|
||||
=== Step 2: Install web server and PHP ===
|
||||
|
||||
You also need to install a web server with PHP5, php5-curl and php-pear.
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo apt-get install apache2 php5 php5-curl php-pear
|
||||
```
|
||||
|
||||
Any web server with PHP support should work.
|
||||
|
||||
=== Step 3: Database installation ===
|
||||
|
||||
Any SQL database with PHP support should work. We give examples for
|
||||
MySQL and PostgreSQL here. Note that you need to chose between either
|
||||
PostgreSQL or MySQL here.
|
||||
|
||||
==== Step 3A: MySQL Installation ====
|
||||
|
||||
Install the required packages:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo apt-get install mysql-server php5-mysql
|
||||
```
|
||||
|
||||
The installation asks you for a MySQL "root" password, and I recommend
|
||||
to specify one. To avoid having to specify a password when using the
|
||||
'mysql' tool interactively, you can store the password in ~/.my.cnf,
|
||||
see /usr/share/doc/mysql-server-5.0/README.Debian.gz. For example:
|
||||
|
||||
```sh
|
||||
user@val:~$ cat > .my.cnf
|
||||
[client]
|
||||
user = root
|
||||
password = YOURPASSWORD
|
||||
user@val:~$ chmod go-r .my.cnf
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
Note the 'chmod' to protect your password from non-root users.
|
||||
|
||||
The database needs to be initialized as follows:
|
||||
|
||||
```sh
|
||||
user@val:~$ echo 'create database ykval' | mysql
|
||||
user@val:~$ mysql ykval < /usr/share/doc/yubikey-val/ykval-db.sql
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
You also need to create a database user for the verifier interface,
|
||||
normally called 'ykval_verifier':
|
||||
|
||||
```sh
|
||||
user@val:~$ mysql --silent ykval
|
||||
mysql> CREATE USER 'ykval_verifier'@'localhost'; \
|
||||
GRANT SELECT,INSERT,UPDATE(modified, yk_counter, yk_low, yk_high, yk_use, nonce) ON ykval.yubikeys TO 'ykval_verifier'@'localhost'; \
|
||||
GRANT SELECT(id, secret, active) ON ykval.clients TO 'ykval_verifier'@'localhost'; \
|
||||
GRANT SELECT,INSERT,UPDATE,DELETE ON ykval.queue TO 'ykval_verifier'@'localhost'; \
|
||||
SET PASSWORD FOR 'ykval_verifier'@'localhost' = PASSWORD('yourpassword'); \
|
||||
FLUSH PRIVILEGES;
|
||||
mysql> \q
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
|
||||
==== Step 3B: PostgreSQL Installation ====
|
||||
|
||||
Install the required packages:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo apt-get install postgresql php5-pgsql
|
||||
...
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
The database needs to be initialized as follows:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo su postgres
|
||||
postgres@val:~$ createdb ykval
|
||||
postgres@val:~$ psql ykval < /usr/share/doc/yubikey-val/ykval-db.sql
|
||||
postgres@val:~$
|
||||
```
|
||||
|
||||
You also need to create a database user for the verifier interface,
|
||||
normally called 'ykval_verifier':
|
||||
|
||||
```sh
|
||||
postgres@val:~$ psql ykval -q
|
||||
ykval=# CREATE USER ykval_verifier PASSWORD 'yourpassword';
|
||||
ykval=# GRANT SELECT,INSERT,UPDATE ON yubikeys TO ykval_verifier;
|
||||
ykval=# GRANT SELECT ON clients TO ykval_verifier;
|
||||
ykval=# GRANT SELECT, INSERT, UPDATE, DELETE ON queue TO ykval_verifier;
|
||||
ykval=# \q
|
||||
postgres@val:~$
|
||||
```
|
||||
|
||||
Don't forget to switch back to your normal user
|
||||
```sh
|
||||
postgres@val:~$ exit
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
During installation and debugging it may be useful to watch the
|
||||
database log entries:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo tail -F /var/log/postgresql/postgresql-*-main.log &
|
||||
```
|
||||
|
||||
=== Step 4: Setup Verify OTP Interface ===
|
||||
|
||||
The interface to verify OTPs is implemented using a PHP script. You
|
||||
can place the script under any URL, but we recommend serving it as
|
||||
'http://ykval.example.org/wsapi/verify'. The simplest way to setup
|
||||
the symlinks is to invoke 'make symlink' in your YK-VAL source tree.
|
||||
Like this:
|
||||
|
||||
```sh
|
||||
user@val:~/yubikey-val$ sudo make symlink
|
||||
install -d /var/www/wsapi/2.0
|
||||
ln -sf /usr/share/yubikey-val/ykval-verify.php /var/www/wsapi/2.0/verify.php
|
||||
ln -sf /usr/share/yubikey-val/ykval-sync.php /var/www/wsapi/2.0/sync.php
|
||||
user@val:~/yubikey-val$
|
||||
```
|
||||
|
||||
If you want to do it manually, you can invoke the above commands
|
||||
manually.
|
||||
|
||||
=== Step 5: Include path configuration ===
|
||||
|
||||
Set the include path for the queue daemon by creating a file
|
||||
/etc/default/ykval-queue with the following content:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat > /etc/default/ykval-queue'
|
||||
DAEMON_ARGS="/etc/yubico/val:/usr/share/yubikey-val"
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
You also need to set the include path for the PHP scripts running via
|
||||
Apache, using a .htaccess file:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat > /var/www/wsapi/2.0/.htaccess'
|
||||
RewriteEngine on
|
||||
RewriteRule ^([^/\.\?]+)(\?.*)?$ $1.php$2 [L]
|
||||
<IfModule mod_php5.c>
|
||||
php_value include_path ".:/etc/yubico/val:/usr/share/yubikey-val"
|
||||
</IfModule>
|
||||
user@val:~$ sudo ln -s 2.0/.htaccess /var/www/wsapi/.htaccess
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
The .htaccess file also sets up rewriting from the non-.PHP suffix URL
|
||||
name to the right script.
|
||||
|
||||
The paths are the default, if you installed the YK-VAL in some other
|
||||
place you need to modify the paths.
|
||||
|
||||
=== Step 6: YK-VAL Configuration ===
|
||||
|
||||
You also need to create a ykval-config.php script. An example file is
|
||||
included in YK-VAL package as ykval-config.php
|
||||
|
||||
A template is typically installed in /etc/yubico/val/ykval-config.php-template.
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo cp /etc/yubico/val/ykval-config.php-template /etc/yubico/val/ykval-config.php
|
||||
user@val:~$ sudo emacs -nw /etc/yubico/val/ykval-config.php
|
||||
```
|
||||
|
||||
Be careful about the user permissions and ownership so that unrelated
|
||||
users on the system cannot read the database password.
|
||||
|
||||
You will typically need to modify the DSN (__YKVAL_DB_DSN__), database
|
||||
passwords (__YKVAL_DB_PW__), the sync pool lists (__YKVAL_SYNC_POOL__
|
||||
and __YKVAL_ALLOWED_SYNC_POOL__), and the YK-KSM URLs inside the
|
||||
otp2ksmurls function.
|
||||
|
||||
An example DSN for a MySQL setup:
|
||||
|
||||
```php
|
||||
$baseParams['__YKVAL_DB_DSN__'] = "mysql:dbname=ykval;host=127.0.0.1";
|
||||
```
|
||||
|
||||
An example DSN for a PostgreSQL setup:
|
||||
|
||||
```php
|
||||
$baseParams['__YKVAL_DB_DSN__'] = "pgsql:dbname=ykval;host=127.0.0.1";
|
||||
```
|
||||
|
||||
We recommend to add the hosts in YKVAL_SYNC_POOL as entries in '/etc/hosts' to avoid network delays caused by DNS-lookups. For example:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat >> /etc/hosts'
|
||||
1.2.3.4 api1.example.com
|
||||
2.3.4.5 api2.example.com
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
|
||||
To improve database performance you can use persistent database connection so that each request doesn't require a new connection to be setup. To enable this modify '__YKVAL_DB_OPTIONS__' as follows:
|
||||
|
||||
```php
|
||||
$baseParams['__YKVAL_DB_OPTIONS__'] = array(PDO::ATTR_PERSISTENT => true);
|
||||
```
|
||||
|
||||
=== Step 7: Apache configuration ===
|
||||
|
||||
Create an apache web configuration file for the normal HTTP interface
|
||||
like this:
|
||||
|
||||
```
|
||||
user@val:~$ sudo sh -c 'cat > /etc/apache2/sites-available/ykval'
|
||||
<VirtualHost *:80>
|
||||
ServerName api.example.com
|
||||
ServerAdmin support@example.com
|
||||
|
||||
DocumentRoot /var/www/
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
<Directory /var/www/>
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
ErrorLog /var/log/apache2/ykval-error.log
|
||||
LogLevel warn
|
||||
|
||||
CustomLog /var/log/apache2/ykval-access.log "%h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
ServerSignature On
|
||||
|
||||
</VirtualHost>
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
HTTPS is strictly speaking not required, but we strongly recommend it.
|
||||
|
||||
You need to install a TLS stack for Apache, there are two popular
|
||||
options here: mod_gnutls and mod_ssl. We'll explain how to install
|
||||
both, but you will need to decide which one to use.
|
||||
|
||||
You will need to create a key/certificate for your server using normal
|
||||
tools like GnuTLS "certtool". A small howto for !GoDaddy is available
|
||||
from
|
||||
[http://permalink.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/4062].
|
||||
|
||||
==== Step 7A: HTTPS via mod_gnutls ====
|
||||
|
||||
First install and enable the mod_gnutls module:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo apt-get install libapache2-mod-gnutls
|
||||
user@val:~$ sudo a2enmod gnutls
|
||||
Enabling module gnutls.
|
||||
Run '/etc/init.d/apache2 restart' to activate new configuration!
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
You will need to place the private key in
|
||||
/etc/ssl/private/api.example.com-key.pem and the certificate chain in
|
||||
/etc/ssl/private/api.example.com-chain.pem.
|
||||
|
||||
Create Apache web configuration files:
|
||||
|
||||
```
|
||||
user@val:~$ sudo sh -c 'cat > /etc/apache2/sites-available/ykval-ssl'
|
||||
Listen 443
|
||||
<VirtualHost *:443>
|
||||
ServerName api.example.com
|
||||
ServerAdmin support@example.com
|
||||
|
||||
GnuTLSEnable on
|
||||
GnuTLSCertificateFile /etc/ssl/private/api.example.com-chain.pem
|
||||
GnuTLSKeyFile /etc/ssl/private/api.example.com-key.pem
|
||||
GnuTLSPriorities NORMAL
|
||||
|
||||
DocumentRoot /var/www/
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
<Directory /var/www/>
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
ErrorLog /var/log/apache2/ykval-ssl-error.log
|
||||
LogLevel warn
|
||||
|
||||
CustomLog /var/log/apache2/ykval-ssl-access.log "%h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
ServerSignature On
|
||||
|
||||
</VirtualHost>
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
==== Step 7B: HTTPS via mod_ssl ====
|
||||
|
||||
The mod_ssl module is typically installed by default, but you need to
|
||||
enable it.
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo a2enmod ssl
|
||||
Enabling module ssl.
|
||||
Run '/etc/init.d/apache2 restart' to activate new configuration!
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
You will need to place the private key in
|
||||
/etc/ssl/private/api.example.com-key.pem and the certificate chain in
|
||||
/etc/ssl/private/api.example.com-chain.pem.
|
||||
|
||||
```
|
||||
user@val:~$ sudo sh -c 'cat > /etc/apache2/sites-available/ykval-ssl'
|
||||
<VirtualHost *:443>
|
||||
ServerName api.example.com
|
||||
ServerAdmin support@example.com
|
||||
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/ssl/private/api.example.com-chain.pem
|
||||
SSLCertificateChainFile /etc/ssl/private/api.example.com-chain.pem
|
||||
SSLCertificateKeyFile /etc/ssl/private/api.example.com-key.pem
|
||||
|
||||
DocumentRoot /var/www/
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
<Directory /var/www/>
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
ErrorLog /var/log/apache2/ykval-ssl-error.log
|
||||
LogLevel warn
|
||||
|
||||
CustomLog /var/log/apache2/ykval-ssl-access.log "%h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
ServerSignature On
|
||||
|
||||
</VirtualHost>
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
==== Common Apache Configuration ====
|
||||
|
||||
This step is the same for both mod_gnutls and mod_ssl.
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo a2enmod rewrite
|
||||
Enabling module rewrite.
|
||||
Run '/etc/init.d/apache2 restart' to activate new configuration!
|
||||
user@val:~$ sudo a2dissite default
|
||||
Site default disabled.
|
||||
Run '/etc/init.d/apache2 reload' to activate new configuration!
|
||||
user@val:~$ sudo a2ensite ykval ykval-ssl
|
||||
Enabling site ykval.
|
||||
Enabling site ykval-ssl.
|
||||
Run '/etc/init.d/apache2 reload' to activate new configuration!
|
||||
user@val:~$ sudo /etc/init.d/apache2 restart
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
=== Step 8: Logging ===
|
||||
|
||||
The PHP interface uses syslog for logging of incoming requests. The
|
||||
facility is LOG_LOCAL0. To place these messages in a separate file,
|
||||
you can add the following to /etc/syslog.conf, or if you use rsyslog,
|
||||
create a file /etc/rsyslog.d/ykval.conf with this content:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat > /etc/rsyslog.d/ykval.conf'
|
||||
local0.* -/var/log/ykval.log
|
||||
user@val:~$ sudo /etc/init.d/rsyslog restart
|
||||
...
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
The '-' before the filename avoids syncing the file after each write,
|
||||
which is recommended for performance.
|
||||
|
||||
The log file can grow large quickly, so it is a good idea to setup
|
||||
rotation of log files. Here is an example that rotates the log file
|
||||
weekly. Create a file /etc/logrotate.d/ykval like this:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat > /etc/logrotate.d/ykval'
|
||||
/var/log/ykval.log {
|
||||
weekly
|
||||
dateext
|
||||
compress
|
||||
missingok
|
||||
rotate 9999
|
||||
notifempty
|
||||
postrotate
|
||||
invoke-rc.d rsyslog reload > /dev/null
|
||||
endscript
|
||||
}
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
You may want to modify the default /etc/logrotate.d/apache2, useful
|
||||
things to add are 'dateext' and 'compress' and change 'rotate' to
|
||||
something large if you want to retain logs.
|
||||
|
||||
=== Step 8.1: Fix default log (optional) ===
|
||||
|
||||
Unfortunately, most default syslog configuration, including the
|
||||
syslog.conf configuration file on Debian, will also log all entries to
|
||||
/var/log/syslog and/or /var/log/messages.
|
||||
|
||||
I am not aware of any way to avoid this without modifying these other
|
||||
rules. To avoid YK-VAL log entries in these other files, you must
|
||||
modify the default rules. For example, edit the following lines of
|
||||
/etc/rsyslog.conf (or /etc/syslog.conf if you don't use rsyslog):
|
||||
|
||||
```
|
||||
*.=debug;\
|
||||
auth,authpriv.none;\
|
||||
news.none;mail.none -/var/log/debug
|
||||
*.*;auth,authpriv.none -/var/log/syslog
|
||||
*.=info;*.=notice;*.=warn;\
|
||||
auth,authpriv.none;\
|
||||
cron,daemon.none;\
|
||||
mail,news.none -/var/log/messages
|
||||
```
|
||||
|
||||
Change them into:
|
||||
|
||||
```
|
||||
*.=debug;\
|
||||
auth,authpriv.none;\
|
||||
news.none;mail.none;local0.none -/var/log/debug
|
||||
*.*;auth,authpriv.none,local0.none -/var/log/syslog
|
||||
*.=info;*.=notice;*.=warn;\
|
||||
auth,authpriv.none;\
|
||||
cron,daemon.none;\
|
||||
local0.none;\
|
||||
mail,news.none -/var/log/messages
|
||||
```
|
||||
|
||||
Idempotent commands to speed this up:
|
||||
|
||||
```sh
|
||||
user@host:~$ sudo perl -pi -e 's/;auth,authpriv.none/;auth,local0.none,authpriv.none/' /etc/rsyslog.conf
|
||||
user@host:~$ sudo perl -pi -e 's/news.none;mail.none/news.none;local0.none;mail.none/' /etc/rsyslog.conf
|
||||
user@host:~$ sudo perl -pi -e 's/cron,daemon.none/cron,daemon.none;local0.none/' /etc/rsyslog.conf
|
||||
user@host:~$ sudo /etc/init.d/rsyslog restart
|
||||
```
|
||||
|
||||
=== Step 9: Start Sync Daemon ===
|
||||
|
||||
When using yubikey-val in a sync pool, you need to have the ykval-queue
|
||||
daemon running to ensure that data is synchronized between the servers in
|
||||
the pool. The easiest way of running this is to simply invoke ykval-queue
|
||||
in a shell:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo ykval-queue
|
||||
```
|
||||
|
||||
However, the recommended approach is to automate running this process in
|
||||
the background, by use of an init script or similar. Instructions on doing
|
||||
so vary depending on your operating system.
|
||||
|
||||
=== Step 10: Sync data from an existing server (optional) ===
|
||||
|
||||
If you're adding a new server to an existing pool, you can synchronize all
|
||||
YubiKey counter data from one of the existing servers. To do so, the server
|
||||
you want to sync from needs to be configured to allow it. Do this by editing
|
||||
/etc/yubico/val/ykval-config.php on the existing server, adding the new
|
||||
servers IP address to the __YKRESYNC_IPS__ setting. You'll most likely want
|
||||
to add the IP to the __YKVAL_ALLOWED_SYNC_POOL__ setting as well. You also
|
||||
need to edit this file on the new server, adding the existing server(s) IP
|
||||
address(es) to __YKVAL_ALLOWED_SYNC_POOL__.
|
||||
|
||||
Once these permissions have been configured, you can initiate the full sync
|
||||
by running the following command from the new server:
|
||||
```sh
|
||||
user@val:~$ ykval-synchronize http://<IP or hostname of existing server>/wsapi/2.0/resync all
|
||||
```
|
||||
|
||||
=== Step 11: Test it ===
|
||||
|
||||
You can test the service by requesting a URL. Using wget, for
|
||||
example:
|
||||
|
||||
```sh
|
||||
user@val:~$ wget -q -O - 'http://localhost/wsapi/2.0/verify?id=1&nonce=asdmalksdmlkasmdlkasmdlakmsdaasklmdlak&otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
|
||||
h=/QVWkl5VlcX+Or1A2b3vOeoLEwI=
|
||||
t=2010-05-17T14:48:15Z0355
|
||||
otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh
|
||||
nonce=asdmalksdmlkasmdlkasmdlakmsdaasklmdlak
|
||||
status=NO_SUCH_CLIENT
|
||||
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
Naturally, you will need to import client keys into the database for
|
||||
the verify function to work properly.
|
||||
|
||||
=== The End ===
|
||||
|
||||
You now have a YK-VAL up and running. See
|
||||
[https://github.com/Yubico/yubikey-ksm/wiki/ServerHardening] on how to
|
||||
improve security of your system.
|
31
doc/MakeRelease.adoc
Normal file
31
doc/MakeRelease.adoc
Normal file
@ -0,0 +1,31 @@
|
||||
==Maintainer instructions for making releases==
|
||||
|
||||
===Introduction===
|
||||
|
||||
The point of this document is to describe all steps required to make a
|
||||
proper release of the yubikey-personalization project.
|
||||
|
||||
===Dependencies===
|
||||
|
||||
Making a release requires the following packages:
|
||||
|
||||
make, git, gnupg, git2cl
|
||||
|
||||
which can be installed (under Ubuntu) by running:
|
||||
|
||||
sudo apt-get install make git gnupg git2cl
|
||||
|
||||
===Details===
|
||||
|
||||
* Make sure the doc/ sub-directory uses the latest revision. Confirm with:
|
||||
cd doc && git checkout master && git pull && git diff
|
||||
|
||||
* Make sure the version number in Makefile has been incremented.
|
||||
|
||||
* Make sure NEWS describes all changes since the last release. Use https://github.com/Yubico/yubikey-val/commits/master to review.
|
||||
|
||||
* Change the '(unreleased)' part in NEWS to '(released 20XX-YY-ZZ)' and commit that with a note 'Version Q.P'.
|
||||
|
||||
* Run 'make release'.
|
||||
|
||||
* Increment version number in Makefile and add a NEWS template for the next release.
|
63
doc/MuninProbes.adoc
Normal file
63
doc/MuninProbes.adoc
Normal file
@ -0,0 +1,63 @@
|
||||
= YK-VAL Munin Plugin =
|
||||
|
||||
Munin is a powerful system monitoring solution. See
|
||||
http://munin-monitoring.org/ for more information. This document
|
||||
documents how to install and enable the YK-VAL Munin plugins on a
|
||||
Munin node. You need to install and configure Munin before following
|
||||
these steps.
|
||||
|
||||
The following Munin plugins are shipped as part of YK-VAL. They make
|
||||
it easy for you to monitor your YK-VAL installation.
|
||||
|
||||
* ykval_ksmlatency: Monitor the latency to each KSM. A useful side
|
||||
effect is that it tests whether the KSM is operational for the
|
||||
particular validation server.
|
||||
|
||||
* ykval_vallatency: Monitor the latency to the other VAL servers, for
|
||||
both IPv4 and IPv6.
|
||||
|
||||
* ykval_queuelength: Monitor the size of the YK-VAL queue.
|
||||
|
||||
The plugins are installed by 'make install' but needs to be configured
|
||||
before they can be used. First create a Munin configuration file to
|
||||
make sure the plugins can access the YK-VAL ykval-config.php
|
||||
configuration file:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat > /etc/munin/plugin-conf.d/ykval'
|
||||
[ykval_ksmlatency]
|
||||
group www-data
|
||||
[ykval_vallatency]
|
||||
group www-data
|
||||
[ykval_queuelength]
|
||||
group www-data
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
Then check that they are working properly:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo /usr/sbin/munin-run --servicedir /usr/share/munin/plugins ykval_queuelength autoconf
|
||||
yes
|
||||
user@val:~$ sudo /usr/sbin/munin-run --servicedir /usr/share/munin/plugins ykval_queuelength config
|
||||
graph_title YK-VAL queue size
|
||||
graph_vlabel sync requests in queue
|
||||
graph_category ykval
|
||||
queuelength.label sync requests
|
||||
queuelength.draw AREA
|
||||
user@val:~$ sudo /usr/sbin/munin-run --servicedir /usr/share/munin/plugins ykval_queuelength
|
||||
queuelength.value 0
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
Enable the plugin as follows:
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo munin-node-configure --shell | sudo sh
|
||||
user@val:~$ sudo /etc/init.d/munin-node restart
|
||||
Stopping Munin-Node: done.
|
||||
Starting Munin-Node: done.
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
After some time, you should see new graphs on your Munin master.
|
61
doc/RevocationService.adoc
Normal file
61
doc/RevocationService.adoc
Normal file
@ -0,0 +1,61 @@
|
||||
= Introduction =
|
||||
|
||||
The YK-VAL server has an optional interface that can be used to
|
||||
enable/disable validation of particular YubiKeys from a remote server.
|
||||
This document explains how to configure and set up that service.
|
||||
|
||||
Currently authorization is based on IP address of client, which may
|
||||
not be secure unless you take additional pre-cautions.
|
||||
|
||||
= Installation =
|
||||
|
||||
```sh
|
||||
user@val:~/yubikey-val$ sudo make revoke
|
||||
user@val:~/yubikey-val$
|
||||
```
|
||||
|
||||
= Configuration =
|
||||
|
||||
Add the following to your /etc/yubico/val/ykval-config.php:
|
||||
|
||||
```php
|
||||
# For the revoke service.
|
||||
$baseParams['__YKREV_IPS__'] = array('10.0.0.1', '2000:1:2:3::4');
|
||||
```
|
||||
|
||||
Obviously you need to modify the IP address.
|
||||
|
||||
You also need to grant additional rights to the database, for MySQL:
|
||||
|
||||
```
|
||||
user@val:~$ mysql --silent ykval
|
||||
mysql> GRANT UPDATE(active) ON ykval.yubikeys to 'ykval_verifier'@'localhost'; \
|
||||
FLUSH PRIVILEGES;
|
||||
mysql> \q
|
||||
user@val:~$
|
||||
```
|
||||
|
||||
For PostgreSQL this should already be working, through this command:
|
||||
|
||||
```
|
||||
postgres@val:~$ psql ykval -q
|
||||
ykval=# GRANT UPDATE ON yubikeys TO ykval_verifier;
|
||||
ykval=# \q
|
||||
postgres@val:~$
|
||||
```
|
||||
|
||||
= Testing =
|
||||
|
||||
Test the installation like this:
|
||||
|
||||
```sh
|
||||
user@revoke:~$ wget -q -O - 'http://api.example.com/wsapi/revoke?yk=dteffujehknh&do=enable'
|
||||
OK Processed dteffujehknh with enable
|
||||
user@revoke:~$
|
||||
```
|
||||
|
||||
Use 'disable' instead of 'enable' to test disabling of the YubiKey.
|
||||
|
||||
= The End =
|
||||
|
||||
You now have the YK-VAL Revocation Service up and running.
|
90
doc/ServerReplicationProtocol.adoc
Normal file
90
doc/ServerReplicationProtocol.adoc
Normal file
@ -0,0 +1,90 @@
|
||||
= Server Replication Protocol =
|
||||
|
||||
This document describes the server to server protocol. Its purpose is
|
||||
to synchronize the last used session and use counter between multiple
|
||||
validation servers.
|
||||
|
||||
Multiple validations servers are connected together so that each
|
||||
validation server can talk to any of the other validation server using
|
||||
the Server Replication Protocol. The validation servers are
|
||||
authenticated by the use of certificates.
|
||||
|
||||
```
|
||||
val A <-> val B <-> val C <-> val A
|
||||
```
|
||||
|
||||
See the ValidationProtocolV20 for definition of the client to server
|
||||
protocol. The protocol described here is the server to server
|
||||
protocol. See ValidationServerAlgorithm for a description of the
|
||||
implementation algorithm that uses this protocol.
|
||||
|
||||
== Sync request specification ==
|
||||
|
||||
A sync request is issued with a HTTP get call, like this:
|
||||
|
||||
```
|
||||
https://apiX.yubico.com/wsapi/sync?otp=xyz&modified=1264430686&nonce=foobar&yk_identity=foo&yk_counter=42&yk_use=17&yk_high=10&yk_low=5
|
||||
```
|
||||
|
||||
The following parameters are used
|
||||
|
||||
{|
|
||||
! parameter !! type !! values
|
||||
|-
|
||||
| otp || string || one-time password (for logging purposes)
|
||||
|-
|
||||
| modified || integer || unix timestamp of when OTP was received
|
||||
|-
|
||||
| nonce || string || nonce from client request
|
||||
|-
|
||||
| yk_identity || modhex || !YubiKey OTP identity in question
|
||||
|-
|
||||
| yk_counter || integer || last seen session counter by sender
|
||||
|-
|
||||
| yk_use || integer || last seen session use by sender
|
||||
|-
|
||||
| yk_high || integer || OTP internal high time value
|
||||
|-
|
||||
| yk_low || integer || OTP internal low time value
|
||||
|}
|
||||
|
||||
Input values for yk_counter, yk_use, yk_high and yk_low are always
|
||||
positive except for -1 which indicates that the requesting server did
|
||||
not have any earlier information about the !YubiKey.
|
||||
|
||||
An example response is
|
||||
|
||||
```sh
|
||||
modified=1264430686
|
||||
nonce=aspodkaaspdokas
|
||||
yk_identity=cccccccccccf
|
||||
yk_counter=api2 session counter
|
||||
yk_use=api2 session use counter
|
||||
yk_high=value
|
||||
yk_low=value
|
||||
```
|
||||
|
||||
The values returned are:
|
||||
|
||||
{|
|
||||
! parameter !! type !! values
|
||||
|-
|
||||
| modified || integer || timestamp of when last OTP was received
|
||||
|-
|
||||
| nonce || string || nonce from client for last OTP
|
||||
|-
|
||||
| yk_identity || modhex || !YubiKey OTP identity in question
|
||||
|-
|
||||
| yk_counter || integer || last seen session counter
|
||||
|-
|
||||
| yk_use || integer || last seen session use
|
||||
|-
|
||||
| yk_high || integer || last seen high time value
|
||||
|-
|
||||
| yk_low || integer || last seen low time value
|
||||
|}
|
||||
|
||||
Output values for modified, yk_counter, yk_use, yk_high and yk_low are
|
||||
always positive except for -1 which indicates that the server did not
|
||||
have any earlier information about the !YubiKey. In this case, nonce
|
||||
is a newly allocated random nonce.
|
29
doc/SyncMonitor.adoc
Normal file
29
doc/SyncMonitor.adoc
Normal file
@ -0,0 +1,29 @@
|
||||
= YK-VAL Synchronization Monitor =
|
||||
|
||||
If you deploy multiple YK-VAL instances, it is important to monitor
|
||||
them to make sure the data they have is synchronized. While there are
|
||||
many mechanisms to achieve this, we provide a simple yet flexible
|
||||
approach. The 'ykval-checksum-clients' tool reads out the important
|
||||
fields from the database and computes a SHA-1 hash of it, and
|
||||
truncates the hash to 10 hex characters and prints them to stdout.
|
||||
|
||||
The "important fields" are currently considered to be the id, active,
|
||||
and secret columns of the clients table.
|
||||
|
||||
The typical way to use this is either manually or to run it in a cron
|
||||
job and output the hash to a file that can be downloaded by a remote
|
||||
monitor system such as Nagios.
|
||||
|
||||
```sh
|
||||
user@val:~$ sudo sh -c 'cat > /etc/cron.hourly/run-ykval-checksum-clients'
|
||||
#!/bin/sh
|
||||
FILE=/var/www/checksum-clients.txt
|
||||
(date --utc +%s; ykval-checksum-clients) > $FILE.tmp
|
||||
mv $FILE.tmp $FILE
|
||||
user@val:~$ sudo chmod +x /etc/cron.hourly/run-ykval-checksum-clients
|
||||
```
|
||||
|
||||
If you notice mismatches, you may want to run ykval-checksum-clients
|
||||
with the '-v' parameter on the different hosts and then use 'diff -ur'
|
||||
or similar tool to compare the outputs. This should make it possible
|
||||
to identify the missmatching entries easily.
|
23
doc/Troubleshooting.adoc
Normal file
23
doc/Troubleshooting.adoc
Normal file
@ -0,0 +1,23 @@
|
||||
= Troubleshooting =
|
||||
|
||||
First check if the web server is working.
|
||||
|
||||
Check that PHP is working. Create a foo.php script containing '<?php
|
||||
phpinfo(); ?>' to debug PHP configuration.
|
||||
|
||||
Next make sure you serve the YK-VAL code under the URL you want, and
|
||||
that accesssing the URL reaches the YK-VAL code. PHP error log in the
|
||||
file set by php.ini error_log, by default /var/log/apache2/error.log.
|
||||
Database errors will also be logged into it.
|
||||
|
||||
The database needs to be started. Make sure you can access it and the
|
||||
tables.
|
||||
|
||||
If 'ykval-export' crashes, you may be running into a compatibility
|
||||
problem between PHP, curl and libpq. See
|
||||
[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=411982] for more
|
||||
information. The workaround is simple:
|
||||
|
||||
```
|
||||
user@val:~$ sudo mv /etc/php5/conf.d/curl.ini /etc/php5/conf.d/z_curl.ini
|
||||
```
|
114
doc/ValidationProtocolV10.adoc
Normal file
114
doc/ValidationProtocolV10.adoc
Normal file
@ -0,0 +1,114 @@
|
||||
= Validation Protocol Version 1.0 =
|
||||
|
||||
== Introduction ==
|
||||
|
||||
All requests are HTTP GETs. As such, all parameters must be properly
|
||||
URL encoded. In particular, some base64 characters (such as "+") in
|
||||
the value fields needs to be escaped.
|
||||
|
||||
Each response sent by Yubico is signed. To make sure the response has
|
||||
not been tampered with, you should verify the signature.
|
||||
|
||||
To verify a signature on a response message, follow the same procedure
|
||||
that was used to sign the response message and compare the signature
|
||||
in the response to the signature you generated. If the signature
|
||||
values are equal, the signature is correct. Make sure you remove the
|
||||
signature itself from the values you generate the signature over for
|
||||
verification. If the incoming message is
|
||||
|
||||
```
|
||||
b=1&a=2&c=3&h=V5FkMYr9GCG9tQA9ihuuybWl99U=
|
||||
```
|
||||
|
||||
make sure to remove h before verifying:
|
||||
|
||||
```
|
||||
b=1&a=2&c=3
|
||||
```
|
||||
|
||||
== Generating signatures ==
|
||||
|
||||
The Yubico API uses HMAC-SHA1 signatures with 160 bit key lengths (as
|
||||
defined by RFC 3174). The HMAC key to use is the API key.
|
||||
|
||||
Generate the signature over the parameters in the message. Each
|
||||
message contains a set of key/value pairs, and the signature is always
|
||||
over the entire set (excluding the signature itself), sorted in
|
||||
alphabetical order of the keys. To generate a message signature:
|
||||
|
||||
# Alphabetically sort the set of key/value pairs by key order.
|
||||
# Construct a single line with each ordered key/value pair concatenated using '&', and each key and value contatenated with '='. Do not add any linebreaks. Do not add whitespace. For example: `a=2&b=1&c=3`.
|
||||
# Apply the signature algorithm to the line's octet string (UTF-8 byte values according to RFC 3629) using the API key as key.
|
||||
# Base 64 encode the resulting value according to RFC 4648, for example, `t2ZMtKeValdA+H0jVpj3LIichn4=`.
|
||||
# Append the value under key h to the message.
|
||||
|
||||
== Verification ==
|
||||
|
||||
There is one call to verify !YubiKey OTPs: verify.
|
||||
|
||||
The verify call lets you check whether an OTP is valid. Since the OTP
|
||||
itself contains identification information, all you have to do is to
|
||||
send the OTP.
|
||||
|
||||
=== Request ===
|
||||
|
||||
Construct an HTTP GET call to
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/verify
|
||||
```
|
||||
|
||||
with the following parameters (note that this request need not be signed):
|
||||
|
||||
{|
|
||||
! parameter !! type !! required !! purpose
|
||||
|-
|
||||
| id || string || Yes || Specifies the requestor so that the end-point can retrieve correct shared secret for signing the response.
|
||||
|-
|
||||
| otp || string || Yes || The OTP from the !YubiKey.
|
||||
|-
|
||||
| h || string || No || The optional HMAC-SHA1 signature for the request.
|
||||
}|
|
||||
|
||||
An example request:
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/verify?otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&id=87
|
||||
```
|
||||
|
||||
=== Response ===
|
||||
|
||||
The verification response tells you whether the OTP is valid. The
|
||||
response has the following values:
|
||||
|
||||
{|
|
||||
! parameter !! type !! purpose
|
||||
|-
|
||||
| h || string (base64) || Signature as described above.
|
||||
|-
|
||||
| t || time stamp || Timestamp in UTC.
|
||||
|-
|
||||
| status || string || The status of the operation, see below.
|
||||
|}
|
||||
|
||||
These are the possible "status" values in a verify response:
|
||||
|
||||
{|
|
||||
! name !! meaning
|
||||
|-
|
||||
| OK || The OTP is valid.
|
||||
|-
|
||||
| BAD_OTP || The OTP is invalid format.
|
||||
|-
|
||||
| REPLAYED_OTP || The OTP has already been seen by the service.
|
||||
|-
|
||||
| BAD_SIGNATURE || The HMAC signature verification failed.
|
||||
|-
|
||||
| MISSING_PARAMETER || The request lacks a parameter.
|
||||
|-
|
||||
| NO_SUCH_CLIENT || The request id does not exist.
|
||||
|-
|
||||
| OPERATION_NOT_ALLOWED || The request id is not allowed to verify OTPs.
|
||||
|-
|
||||
| BACKEND_ERROR || Unexpected error in our server. Please contact us if you see this error.
|
||||
|}
|
139
doc/ValidationProtocolV11.adoc
Normal file
139
doc/ValidationProtocolV11.adoc
Normal file
@ -0,0 +1,139 @@
|
||||
= Validation Protocol Version 1.1 =
|
||||
|
||||
== Introduction ==
|
||||
|
||||
All requests are HTTP GETs. As such, all parameters must be properly
|
||||
URL encoded. In particular, some base64 characters (such as "+") in
|
||||
the value fields needs to be escaped.
|
||||
|
||||
Each response sent by Yubico is signed. To make sure the response has
|
||||
not been tampered with, you should verify the signature.
|
||||
|
||||
To verify a signature on a response message, follow the same procedure
|
||||
that was used to sign the response message and compare the signature
|
||||
in the response to the signature you generated. If the signature
|
||||
values are equal, the signature is correct. Make sure you remove the
|
||||
signature itself from the values you generate the signature over for
|
||||
verification. If the incoming message is
|
||||
|
||||
```
|
||||
b=1&a=2&c=3&h=V5FkMYr9GCG9tQA9ihuuybWl99U=
|
||||
```
|
||||
|
||||
make sure to remove h before verifying:
|
||||
|
||||
```
|
||||
b=1&a=2&c=3
|
||||
```
|
||||
|
||||
== Generating signatures ==
|
||||
|
||||
The Yubico API uses HMAC-SHA1 signatures with 160 bit key lengths (as
|
||||
defined by RFC 3174). The HMAC key to use is the API key.
|
||||
|
||||
Generate the signature over the parameters in the message. Each
|
||||
message contains a set of key/value pairs, and the signature is always
|
||||
over the entire set (excluding the signature itself), sorted in
|
||||
alphabetical order of the keys. To generate a message signature:
|
||||
|
||||
# Alphabetically sort the set of key/value pairs by key order.
|
||||
# Construct a single line with each ordered key/value pair concatenated using '&', and each key and value contatenated with '='. Do not add any linebreaks. Do not add whitespace. For example: `a=2&b=1&c=3`.
|
||||
# Apply the signature algorithm to the line's octet string (UTF-8 byte values according to RFC 3629) using the API key as key.
|
||||
# Base 64 encode the resulting value according to RFC 4648, for example, `t2ZMtKeValdA+H0jVpj3LIichn4=`.
|
||||
# Append the value under key h to the message.
|
||||
|
||||
== Verification ==
|
||||
|
||||
There is one call to verify YubiKey OTPs: verify.
|
||||
|
||||
The verify call lets you check whether an OTP is valid. Since the OTP
|
||||
itself contains identification information, all you have to do is to
|
||||
send the OTP.
|
||||
|
||||
=== Request ===
|
||||
|
||||
Construct an HTTP GET call to
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/verify
|
||||
```
|
||||
|
||||
with the following parameters (note that this request need not be signed):
|
||||
|
||||
{|
|
||||
! parameter !! type !! required !! purpose
|
||||
|-
|
||||
| id || string || Yes || Specifies the requestor so that the end-point can retrieve correct shared secret for signing the response.
|
||||
|-
|
||||
| otp || string || Yes || The OTP from the !YubiKey.
|
||||
|-
|
||||
| h || string || No || The optional HMAC-SHA1 signature for the request.
|
||||
|-
|
||||
| timestamp || string || No || Timestamp=1 requests timestamp and session counter information the response
|
||||
|}
|
||||
|
||||
An example request:
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/verify?otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&id=87
|
||||
```
|
||||
|
||||
And if you require additional information on timestamp and session
|
||||
counters:
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/verify?otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&id=87×tamp=1
|
||||
```
|
||||
|
||||
=== Response ===
|
||||
|
||||
The verification response tells you whether the OTP is valid. The
|
||||
response has the following values:
|
||||
|
||||
{|
|
||||
! parameter !! type !! purpose
|
||||
|-
|
||||
| h || string (base64) || Signature as described above.
|
||||
|-
|
||||
| t || time stamp || Timestamp in UTC.
|
||||
|-
|
||||
| status || string || The status of the operation, see below.
|
||||
|-
|
||||
| timestamp || string || !YubiKey internal timestamp value when key was pressed
|
||||
|-
|
||||
| sessioncounter || string || !YubiKey internal usage counter when key was pressed
|
||||
|-
|
||||
| sessionuse || string || !YubiKey internal session usage counter when key was pressed
|
||||
|}
|
||||
|
||||
These are the possible "status" values in a verify response:
|
||||
|
||||
{|
|
||||
! name !! meaning
|
||||
|-
|
||||
| OK || The OTP is valid.
|
||||
|-
|
||||
| BAD_OTP || The OTP is invalid format.
|
||||
|-
|
||||
| REPLAYED_OTP || The OTP has already been seen by the service.
|
||||
|-
|
||||
| BAD_SIGNATURE || The HMAC signature verification failed.
|
||||
|-
|
||||
| MISSING_PARAMETER || The request lacks a parameter.
|
||||
|-
|
||||
| NO_SUCH_CLIENT || The request id does not exist.
|
||||
|-
|
||||
| OPERATION_NOT_ALLOWED || The request id is not allowed to verify OTPs.
|
||||
|-
|
||||
| BACKEND_ERROR || Unexpected error in our server. Please contact us if you see this error.
|
||||
|}
|
||||
|
||||
== Changes since version 1.0 ==
|
||||
|
||||
In the request, the new optional parameter "timestamp" were added. In
|
||||
the response, the parameters "timestamp", "sessioncounter",
|
||||
"sessionuse" were added, which are only present when the request
|
||||
contained the "timestamp" parameter.
|
||||
|
||||
The protocol is thus fully backwards compatible. All possible version
|
||||
1 requests are still valid version 1.1 requests.
|
168
doc/ValidationProtocolV20.adoc
Normal file
168
doc/ValidationProtocolV20.adoc
Normal file
@ -0,0 +1,168 @@
|
||||
= Validation Protocol Version 2.0 =
|
||||
|
||||
== Introduction ==
|
||||
|
||||
All requests are HTTP GET requests. As such, all parameters must be
|
||||
properly URL encoded. In particular, some base64 characters (such as
|
||||
"+") in the value fields needs to be escaped.
|
||||
|
||||
Each response sent by the server is signed. To verify that the
|
||||
response has not been tampered with, clients either verify the HMAC
|
||||
signature or use HTTPS connections (and verify the server
|
||||
certificate).
|
||||
|
||||
== Generating signatures ==
|
||||
|
||||
The protocol uses HMAC-SHA-1 signatures. The HMAC key to use is the
|
||||
client API key.
|
||||
|
||||
Generate the signature over the parameters in the message. Each
|
||||
message contains a set of key/value pairs, and the signature is always
|
||||
over the entire set (excluding the signature itself), and sorted in
|
||||
alphabetical order of the keys. More precisely, to generate a message
|
||||
signature do:
|
||||
|
||||
# Alphabetically sort the set of key/value pairs by key order.
|
||||
# Construct a single line with each ordered key/value pair concatenated using '&', and each key and value contatenated with '='. Do not add any linebreaks. Do not add whitespace. For example: `a=2&b=1&c=3`.
|
||||
# Apply the HMAC-SHA-1 algorithm on the line as an octet string using the API key as key.
|
||||
# Base 64 encode the resulting value according to RFC 4648, for example, `t2ZMtKeValdA+H0jVpj3LIichn4=`.
|
||||
# Append the value under key 'h' to the message.
|
||||
|
||||
== Verifying signatures ==
|
||||
|
||||
To verify a signature on a response message, follow the same procedure
|
||||
that was used to sign the response message and compare the signature
|
||||
in the response to the signature you generated. If the signature
|
||||
values are equal, the signature is correct. Make sure you remove the
|
||||
signature itself from the values you generate the signature over for
|
||||
verification. If the incoming message is
|
||||
|
||||
```
|
||||
b=1&a=2&c=3&h=V5FkMYr9GCG9tQA9ihuuybWl99U=
|
||||
```
|
||||
|
||||
make sure to remove h before verifying:
|
||||
|
||||
```
|
||||
b=1&a=2&c=3
|
||||
```
|
||||
|
||||
Don't forget to sort the key/value pairs.
|
||||
|
||||
== Verification ==
|
||||
|
||||
There is one call to verify !YubiKey OTPs: verify.
|
||||
|
||||
The verify call lets you check whether an OTP is valid. Since the OTP
|
||||
itself contains identification information, all you have to do is to
|
||||
send the OTP.
|
||||
|
||||
To avoid cut'n'paste attacks, the client MUST verify that the "otp" in
|
||||
the response is the same as the "otp" supplied in the request.
|
||||
|
||||
=== Request ===
|
||||
|
||||
Construct an HTTP GET call to
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/2.0/verify
|
||||
```
|
||||
|
||||
with the following parameters (note that this request need not be signed):
|
||||
|
||||
{|
|
||||
! parameter !! type !! required !! purpose
|
||||
|-
|
||||
| id || string || Yes || Specifies the requestor so that the end-point can retrieve correct shared secret for signing the response.
|
||||
|-
|
||||
|otp || string || Yes || The OTP from the !YubiKey.
|
||||
|-
|
||||
| h || string || No || The optional HMAC-SHA1 signature for the request.
|
||||
|-
|
||||
| timestamp || string || No || Timestamp=1 requests timestamp and session counter information in the response
|
||||
|-
|
||||
| nonce || string || Yes || A 16 to 40 character long string with random unique data
|
||||
|-
|
||||
| sl || string || No || A value 0 to 100 indicating percentage of syncing required by client, or strings "fast" or "secure" to use server-configured values; if absent, let the server decide
|
||||
|-
|
||||
| timeout || integer || No || Number of seconds to wait for sync responses; if absent, let the server decide
|
||||
|}
|
||||
|
||||
An example request:
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/2.0/verify?otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&id=87&timeout=8&sl=50&nonce=askjdnkajsndjkasndkjsnad
|
||||
```
|
||||
|
||||
And if you require additional information on timestamp and session
|
||||
counters:
|
||||
|
||||
```
|
||||
http://api.yubico.com/wsapi/2.0/verify?id=87&otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&timeout=8&sl=50&nonce=askjdnkajsndjkasndkjsnad×tamp=1
|
||||
```
|
||||
|
||||
=== Response ===
|
||||
|
||||
The verification response tells you whether the OTP is valid. The
|
||||
response has the following values:
|
||||
|
||||
{|
|
||||
! parameter !! type !! purpose
|
||||
|-
|
||||
| otp || string || The OTP from the !YubiKey, from request.
|
||||
|-
|
||||
| nonce || string || Random unique data, from request.
|
||||
|-
|
||||
| h || string (base64) || Signature as described above.
|
||||
|-
|
||||
| t || time stamp || Timestamp in UTC.
|
||||
|-
|
||||
| status || string || The status of the operation, see below.
|
||||
|-
|
||||
| timestamp || string || !YubiKey internal timestamp value when key was pressed
|
||||
|-
|
||||
| sessioncounter || string || !YubiKey internal usage counter when key was pressed
|
||||
|-
|
||||
| sessionuse || string || !YubiKey internal session usage counter when key was pressed
|
||||
|-
|
||||
| sl || integer || percentage of external validation server that replied successfully (0 to 100)
|
||||
|}
|
||||
|
||||
These are the possible "status" values in a verify response:
|
||||
|
||||
{|
|
||||
! name !! meaning
|
||||
|-
|
||||
| OK || The OTP is valid.
|
||||
|-
|
||||
| BAD_OTP || The OTP is invalid format.
|
||||
|-
|
||||
| REPLAYED_OTP || The OTP has already been seen by the service.
|
||||
|-
|
||||
| BAD_SIGNATURE || The HMAC signature verification failed.
|
||||
|-
|
||||
| MISSING_PARAMETER || The request lacks a parameter.
|
||||
|-
|
||||
| NO_SUCH_CLIENT || The request id does not exist.
|
||||
|-
|
||||
| OPERATION_NOT_ALLOWED || The request id is not allowed to verify OTPs.
|
||||
|-
|
||||
| BACKEND_ERROR || Unexpected error in our server. Please contact us if you see this error.
|
||||
|-
|
||||
| NOT_ENOUGH_ANSWERS || Server could not get requested number of syncs during before timeout
|
||||
|-
|
||||
| REPLAYED_REQUEST || Server has seen the OTP/Nonce combination before
|
||||
|}
|
||||
|
||||
== Changes since version 1.1 ==
|
||||
|
||||
The verify URL has changed. In the request, the new required field
|
||||
"nonce" were added, and the new optional fields "sl" and "timeout" are
|
||||
added. In the response, the new fields "otp", "nonce", and "sl" are
|
||||
added. The status codes NOT_ENOUGH_ANSWERS and REPLAYED_REQUEST were
|
||||
added.
|
||||
|
||||
Since both the URL and required fields has changed, version 2.0 is not
|
||||
backwards compatible with version 1.1 or version 1.0. However,
|
||||
because version 2.0 use a different URL than version 1.x, the server
|
||||
may support both version 1.x and version 2.0 clients at the same time.
|
193
doc/ValidationServerAlgorithm.adoc
Normal file
193
doc/ValidationServerAlgorithm.adoc
Normal file
@ -0,0 +1,193 @@
|
||||
= Validation Server Algorithm =
|
||||
|
||||
This document describes how a validation server should be implemented,
|
||||
and the required steps it needs to perform in order to be secure.
|
||||
|
||||
The client-to-server protocol is described in ValidationProtocolV20
|
||||
and the server-to-server protocol is described in
|
||||
ServerReplicationProtocol.
|
||||
|
||||
== Normal validation with Sync ==
|
||||
|
||||
Val X receives an OTP verify request and needs to update the other
|
||||
validation servers on the last seen counter values. The procedure is
|
||||
as follows
|
||||
|
||||
# Val X parses validation request, retrieves the client key for the client id from local database and checks the request signature.
|
||||
# Val X decrypts the OTP using a KSM and reads out the modified/counters from the internal database -- if the YubiKey identity doesn't exist in the database, add it with counter/use/high/low=-1.
|
||||
# Val X checks the OTP/Nonce against local database, and replies with REPLAYED_REQUEST if local information is identical.
|
||||
# Val X checks the OTP counters against local counters, and rejects OTP as replayed if local counters are higher than or equal to OTP counters.
|
||||
# Val X updates the internal database with counters/nonce from request.
|
||||
# Val X queues a sync request in a sync queue for each validation server in the validation server pool (manually configured).
|
||||
# Val X requests the queued requests (otp, modified, nonce, yk_identity, yk_counter, yk_use, yk_high, yk_low) to be sent out, by sending parallel sync requests to all other validation servers.
|
||||
# Each validation server receiving a sync request updates its own internal database with received information to use the highest counter.
|
||||
# Each remote server responds with a sync response (modified, nonce, yk_identity, yk_counter, yk_use, yk_high, yk_low) using data from its internal database.
|
||||
# Val X waits for a sync response (up until timeout, or when sufficient number of sync responses indicating valid OTP and no sync response indicating invalid OTP) from the other validation servers to which it sent a sync request. For each response that arrives the corresponding entry in the sync queue is removed and the following is checked
|
||||
## If the sync response counters have higher values than val X internal database, the internal database is updated with new information, AND
|
||||
## If the sync response counter have higher values as val X internal database the response is considered to mark the OTP as invalid, AND
|
||||
## If the sync response have equal counter values and nonce as val X internal database the response is considered to mark the OTP as valid, AND
|
||||
## If the sync response have equal counter values and different nonce as val X internal database the response is considered to mark the OTP as invalid, AND
|
||||
## If the sync response counter have smaller values than val X had in its internal database before the validation attempt the server logs a warning, and the response is considered to mark the OTP as valid.
|
||||
# Val X construct validation response. Validation is successful if the Verification Algorithm below is successful.
|
||||
# Val X marks the remaining entries in the sync queue as marked with timestamp=NULL.
|
||||
|
||||
Any remaining sync requests in the sync queue are from now on handled
|
||||
by a background daemon which re-sends them at regular intervals
|
||||
(described below).
|
||||
|
||||
=== Verification algorithm ===
|
||||
|
||||
```sh
|
||||
Input:
|
||||
otp - the otp
|
||||
nonce - the nonce from the request
|
||||
yk:counter - the session counter
|
||||
yk:use - the session use counter
|
||||
yk:high - the high timestamp
|
||||
yk:low - the low timestamp
|
||||
modified - when the counters were last modified
|
||||
|
||||
Output:
|
||||
Error code.
|
||||
```
|
||||
|
||||
Val X requires that SL % of the sent sync requests gives a response
|
||||
marking the OTP as valid, and that none of the responses indicate the
|
||||
OTP is invalid, in order to consider the OTP to be valid.
|
||||
|
||||
# If internal database counters are equal to otp counters AND nonce is identical, then return REPLAYED_REQUEST.
|
||||
# If internal database counters are higher/equal to otp counters, then return REPLAYED_OTP.
|
||||
# If any counter in sync response are higher/equal to otp counters, then return REPLAYED_OTP.
|
||||
# If insufficient number of sync responses are received, then return NOT_ENOUGH_ANSWERS.
|
||||
# (optional: if phishing test fails, return DELAYED_OTP)
|
||||
# return OK
|
||||
|
||||
=== Warning algorithm ===
|
||||
|
||||
Warn if any of these are true:
|
||||
|
||||
* If received sync response have lower counters than locally saved last counters (indicating that remote server wasn't synced)
|
||||
|
||||
* If received sync response have higher counters than locally saved last counters (indicating that local server wasn't synced)
|
||||
|
||||
* If received sync response have counters higher than or equal to the OTP counters (indicating that the OTP is replayed)
|
||||
|
||||
* If received sync request have counters equal to local counters and modified field equal to local modified field (sync request has been unnecessarily resent).
|
||||
|
||||
* If received sync request have counters equal to local counters and modified field different to local modified field (We might have a replay. 2 events at different times have generated the same counters)
|
||||
|
||||
* If received sync request have lower counters than local (indicating that remote server is not synced)
|
||||
|
||||
* If received sync request have identical counters but different nonce (indicating that remote server received a request to validate an already validated OTP)
|
||||
|
||||
=== Update validation server that has been offline ===
|
||||
|
||||
Val X has been out of function and its internal database needs to be
|
||||
updated.
|
||||
|
||||
This case is handled automatically since the sync requests which did
|
||||
not succeed immediately in the previous point are queued.
|
||||
|
||||
When val X is accessible again, all the sync requests in queue are
|
||||
re-sent and val X database is updated.
|
||||
|
||||
Responses which would have caused the sender of the sync request to
|
||||
consider the OTP as invalid will give raise to a warning on the sender
|
||||
validation server.
|
||||
|
||||
== Sync queue daemon ==
|
||||
|
||||
There is one queue daemon that is responsible for sending all the
|
||||
queued requests.
|
||||
|
||||
The sync queue will loop the following algorithm.
|
||||
|
||||
# Get a list of all remote server from the database; S1, S2, ...
|
||||
# For each remote server S in the list S1, S2, ... do
|
||||
## For each entry in the queue table for S which have a queued_time==NULL or a timestamp older than a configured period (e.g., one minute) do
|
||||
### Send one request, using a configured timeout value (e.g., 30 seconds).
|
||||
### If the request is unsuccessful (or times out), quit to the outer loop.
|
||||
### The request was successful so the sync daemon receives counter/nonce values from the remote server.
|
||||
### If the sync response counters are lower, give a warning
|
||||
### If the sync response counters are equal and nonce different, give a warning
|
||||
### If the sync response counter have higher than or equal values as val X internal database had at the moment of request creation a warning is logged.
|
||||
### The sync daemon updates the internal database to use the highest counter values: {{{UPDATE yubikeys SET counter = X, sessionUse = Y, high = P, low = Q, nonce = N, accessed = D WHERE publicName = ID AND ((counter < X) OR (counter = X AND sessionUse < Y))}}}
|
||||
### The corresponding entry in the sync queue is removed.
|
||||
|
||||
= Logging matrix =
|
||||
|
||||
Available parameters in comparisons are the following.
|
||||
|
||||
{|
|
||||
| local || Local parameters at time of comparison
|
||||
|-
|
||||
| otp || Parameters from OTP provided in validation request
|
||||
|-
|
||||
| response || Parameters in sync respone
|
||||
|-
|
||||
| request || Parameters in sync request
|
||||
|-
|
||||
| validation || Local parameters when OTP vaildation request arrived
|
||||
|}
|
||||
Parameters could be counters, modified, nonce.
|
||||
|
||||
== Non-queued Sync response logging ==
|
||||
|
||||
We compare reponse parameters against validation parameters since we
|
||||
are interested in if the server is in sync at the moment when the
|
||||
validation request arrives.
|
||||
|
||||
{|
|
||||
! condition !! level !! action !! message
|
||||
|-
|
||||
| response.counters < validation.counters || Notice || None || Remote server out of sync.
|
||||
|-
|
||||
| response.counters > validation.counters || Notice || None ||Local server out of sync.
|
||||
|-
|
||||
| response.counters = validation.counters and response.nonce != validation.nonce || Notice || None || Servers out of sync. Nonce differs.
|
||||
|-
|
||||
| response.counters = validation.counters and response.modified != validation.modified || Notice || None || Servers out of sync. Modified differs.
|
||||
|-
|
||||
| response.counters > otp.counters || Warning || OTP marked as invalid ||OTP is replayed. Sync response counters higher than OTP counters
|
||||
|-
|
||||
| response.counter = otp.counters and response.nonce != otp.nonce || Warning || OTP marked as invalid || OTP is replayed. Sync response counters equal to OTP counters and nonce differs.
|
||||
|}
|
||||
|
||||
== Sync request logging ==
|
||||
|
||||
Both an original sync and a queued sync looks the same so we can not
|
||||
determine if the sync is original or queued. Therefore the logging is
|
||||
the same in both cases.
|
||||
|
||||
{|
|
||||
! condition !! level !! message !! note
|
||||
|-
|
||||
| request.counters < local.counters || Warning || Remote server out of sync. ||
|
||||
|-
|
||||
| request.counters = local.counters and request.modified = local.modifed and request.nonce = local.nonce || Notice || Sync request has been unnecessarily resent. || This could happen frequently whenever a syncentry is queued but the syncprocess terminates before the resonse to the syncentry arrives (since SL level was already achived).
|
||||
|-
|
||||
| request.counters = local.counters and request.modified != local.modified and request.nonce = local.nonce || Warning || We might have a replay. 2 events at different times have generated the same counters. The time difference is X seconds ||
|
||||
|-
|
||||
| request.counters = local.counters and request.nonce != local.nonce || Warning || Remote server has received a request to validate an already validated OTP ||
|
||||
|}
|
||||
|
||||
== Queued sync response logging ==
|
||||
|
||||
What do we want to warn for here. Out of sync at time of OTP
|
||||
validation request or out of sync compared to current local counters?
|
||||
|
||||
{|
|
||||
! condition !! level !! message !! note
|
||||
|-
|
||||
| response.counters < validation.counters || Notice || Remote server out of sync compared to counters at validation request time. ||
|
||||
|-
|
||||
| response.counters > validation.counters || Notice || Local server out of sync compared to counters at validation request time. ||
|
||||
|-
|
||||
| response.counters < local.counters || Warning || Remote server out of sync compared to current local counters. ||
|
||||
|-
|
||||
| response.counters > local.counters || Warning || Local server out of sync compared to current local counters. Local server updated. ||
|
||||
|-
|
||||
| response.counters > otp.counters || Error || Remote server has higher counters than OTP. This response would have marked the OTP as invalid. ||
|
||||
|-
|
||||
| response.counter = otp.counters and response.nonce != otp.nonce || Error || Remote server has equal counters as OTP and nonce differs. This response would have marked the OTP as invalid. ||
|
||||
|}
|
42
doc/YubiKeyInfoFormat.adoc
Normal file
42
doc/YubiKeyInfoFormat.adoc
Normal file
@ -0,0 +1,42 @@
|
||||
=Format of YubiKey Info Data=
|
||||
|
||||
This file holds data used in the YubiKey OTP validation phase.
|
||||
|
||||
Each of the lines in the file follows the following format:
|
||||
|
||||
```
|
||||
active,created,modified,yk_publicname,yk_counter,yk_use,yk_low,yk_high,nonce,notes
|
||||
```
|
||||
|
||||
Any empty line, or a line beginning with a # is ignored.
|
||||
|
||||
The meaning are as follows:
|
||||
;active
|
||||
: the YubiKey state, 1 if active, 0 if not
|
||||
;created
|
||||
: unix timestamp of when the YubiKey entry was created, decimal integer
|
||||
;modified
|
||||
: unix timestamp of when the YubiKey entry was last modified, decimal integer
|
||||
;yk_publicname
|
||||
: the public id of the YubiKey, modhex string
|
||||
;yk_counter
|
||||
: the YubiKey session counter, decimal integer
|
||||
;yk_use
|
||||
: the YubiKey use counter, decimal integer
|
||||
;yk_low
|
||||
: the low part of the YubiKey timestamp counter, decimal integer
|
||||
;yk_high
|
||||
: the high part of the YubiKey timestamp counter, decimal integer
|
||||
;nonce
|
||||
: the nonce used for the last validation request, ascii printable string
|
||||
;notes
|
||||
: not used, printable ascii string
|
||||
|
||||
An example of a valid data line:
|
||||
|
||||
```
|
||||
1,1359470658,1359470658,cccccccccccb,2,1,32729,4,aoincuhfuahs
|
||||
```
|
||||
|
||||
For an example of importing and exporting YubiKey Info data, please see
|
||||
[[ImportExportData|Importing and Exporting Data]].
|
Loading…
x
Reference in New Issue
Block a user