1
0
mirror of https://github.com/Yubico/yubikey-ksm.git synced 2024-11-29 00:24:14 +01:00

Add wiki pages.

This commit is contained in:
Simon Josefsson 2014-09-19 15:02:49 +02:00
parent 11bd81fa2f
commit a8f21ebe02
10 changed files with 998 additions and 0 deletions

View File

@ -0,0 +1,36 @@
== Yubikey KSM Decryption Protocol ==
The protocol for asking the Yubikey Key Storage Module to decrypt an
OTP is to request a HTTP resource as follows:
http://ykksm.example.com/wsapi/decrypt/?otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh
On success, the response will follow this format:
^OK .*
For example:
OK counter=000f low=c541 high=a7 use=04
The content of the various fields are as follows:
* '''counter''': 16-bit hex integer, counting upwards on each powerup&touch
* '''low''': 16-bit hex integer, low part of time-stamp of OTP
* '''high''': 8-bit hex integer, high part of time-stamp of OTP
* '''use''': 8-bit hex integer, counting upwards on each touch
On soft errors, the response will follow this format:
^ERR .*
For example:
ERR Invalid OTP format
The data matching .* will be a english error message in one line.
Any other kind of response means a hard error occured.

9
doc/DesignGoals.txt Normal file
View File

@ -0,0 +1,9 @@
== YK-KSM Design Goals ==
The YK-KSM component was designed for these objectives:
* Have AES key storage be separate from the validation server
* Allow distribution of AES keys to multiple servers for load-balancing and high-availability
* The code must be short and easy to audit

70
doc/GenerateKSMKey.txt Normal file
View File

@ -0,0 +1,70 @@
== Generate KSM Key ==
Import of key material to an YK-KSM is typically always done via the
OpenPGP encrypted/signed KeyProvisioningFormat format. This setup
assumes that each YK-KSM system has a private key.
Below is a walk-through of a typical key generation session for a host
called 'crater'. As you can see at the end, it generated a key with a
key id of '8B88A11B'.
After this step you may want to generate AES keys for your YubiKeys,
see [[GenerateKeys]], and then import them to your KSM, see
[[ImportKeysToKSM]].
user@crater:~$ gpg --gen-key
gpg (GnuPG) 1.4.9; Copyright (C) 2008 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) DSA and Elgamal (default)
(2) DSA (sign only)
(5) RSA (sign only)
Your selection? 1
DSA keypair will have 1024 bits.
ELG-E keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: YK-KSM crater Import Key
Email address:
Comment:
You selected this USER-ID:
"YK-KSM crater Import Key"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
You need a Passphrase to protect your secret key.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
.+++++++++++++++++++++++++..+++++.+++++++++++++++++++++++++...+++++++++++++++.++++++++++.++++++++++++++++++++++++++++++++++++++++.++++++++++>++++++++++......++++++++++..++++++++++++++++++++..++++++++++++++++++++++++++++++++++++++++....+++++.+++++...+++++.++++++++++.+++++++++++++++.+++++..+++++.++++++++++.+++++++++++++++..+++++>++++++++++>+++++.................................>+++++..............+++++^^^
gpg: /home/user/.gnupg/trustdb.gpg: trustdb created
gpg: key 8B88A11B marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 1024D/8B88A11B 2009-12-14
Key fingerprint = 9B18 20A2 F02E 3C3B 84E3 44F5 AE72 7967 8B88 A11B
uid YK-KSM crater Import Key
sub 2048g/140A17F1 2009-12-14
user@crater:~$

78
doc/GenerateKeys.txt Normal file
View File

@ -0,0 +1,78 @@
== Generate Keys ==
To generate some AES keys for your !YubiKeys served via your YK-KSM,
you use the 'ykksm-gen-keys' tool. The tool is useful for generating
large sets of test keys, for performance testing of the database and
web interface. It can also be used to produce keying material that
are intended to used for programming real keys.
As you should never store encryption keys in plaintext, you typically
use the tool by piping it directly to GnuPG. So the first step will
always be to create a OpenPGP key for your KSM host, see
[[GenerateKSMKey]]. Below we will both sign the data from and encrypt
it to the same key id '8B88A11B'. Here is how you would generate 5
keys for test purposes:
user@ksm:~$ ykksm-gen-keys --urandom 1 5 | gpg -a --encrypt -r 8B88A11B -s > keys.txt
user@ksm:~$
Note the flag --urandom will cause the tool to use /dev/urandom rather
than /dev/random, which speed things up but is considered by some to
have weaker security.
After this step you may want to import the keys into your KSM, see
[[ImportKeysToKSM]].
In production, you may want to separate the key generation facility
into a separate machine with a separate OpenPGP key.
To display the test keys above, you can decrypt them using GnuPG:
<nowiki>user@ksm:~$ gpg < keys.txt
You need a passphrase to unlock the secret key for
user: "YK-KSM crater Import Key"
2048-bit ELG-E key, ID 140A17F1, created 2009-12-14 (main key ID 8B88A11B)
gpg: encrypted with 2048-bit ELG-E key, ID 140A17F1, created 2009-12-14
"YK-KSM crater Import Key"
# ykksm 1
# serialnr,identity,internaluid,aeskey,lockpw,created,accessed[,progflags]
1,cccccccccccb,d74fbdf6a890,82211e0854e7369e83d941f24761a84e,881ae7bee927,2009-12-14T16:40:57,
2,cccccccccccd,7a5ad1886b70,3091a8048524ab8407ae816457d764e5,8e5ab609e346,2009-12-14T16:40:57,
3,ccccccccccce,981abbbeafb8,91be4bfd2f40e24ebd39386868aa9619,037b6f6ae73c,2009-12-14T16:40:57,
4,cccccccccccf,c1f33c17f77b,a2389839d7b80bfe4c80258184aff4ce,abf92cbbdab3,2009-12-14T16:40:57,
5,cccccccccccg,c55773192393,7387b5f6bede83f64a9cd75b2023826a,d70c937bbbff,2009-12-14T16:40:57,
gpg: Signature made Mon 14 Dec 2009 04:40:57 PM CET using DSA key ID 8B88A11B
gpg: Good signature from "YK-KSM crater Import Key"
user@ksm:~$</nowiki>
The format is documented in the KeyProvisioningFormat wiki page.
To generate many small files each containing just one key, you can use
a small wrapper like this:
<nowiki>#!/bin/sh
set -e
start=$1
stop=$2
key=$3
urandom=$4
if test -z "$start" || test -z "$stop" || test -z "$key"; then
echo "Usage: run-gen-keys START STOP KEY [--urandom]"
echo ""
echo "Example usage:"
echo " run-gen-keys 4711 11147 A1296239 --urandom"
echo ""
exit 0
fi
cur=$start
while test $cur -le $stop; do
ykksm-gen-keys $urandom $cur | gpg -a --sign --encrypt -r $key > $cur.asc
cur=`expr $cur + 1`
done</nowiki>

78
doc/ImportKeysToKSM.txt Normal file
View File

@ -0,0 +1,78 @@
== Import Keys To Yubikey KSM ==
To import keys into the YK-KSM database from text files in the
encrypted/signed KeyProvisioningFormat format, you can use the tool
'ykksm-import'. The tool reads the data on standard input, and will
import the data to the database. On any error, execution is aborted,
so be careful about partial imports leaving the database in an
intermediate state.
The tool requires that your system has a GnuPG private key, read
[[GenerateKSMKey]] on how to generate it.
For example, to import the file generated by the [[GenerateKeys]]
document:
<nowiki>
user@ksm:~$ ykksm-import --verbose --database 'DBI:Pg:dbname=ykksm;host=127.0.0.1' --db-user ykksmimporter --db-passwd otherpassword < ~/keys.txt
You need a passphrase to unlock the secret key for
user: "YK-KSM crater Import Key"
2048-bit ELG-E key, ID 140A17F1, created 2009-12-14 (main key ID 8B88A11B)
Verification output:
[GNUPG:] ENC_TO 8C73EAF1140A17F1 16 0
[GNUPG:] USERID_HINT 8C73EAF1140A17F1 YK-KSM crater Import Key
[GNUPG:] NEED_PASSPHRASE 8C73EAF1140A17F1 AE7279678B88A11B 16 0
[GNUPG:] GOOD_PASSPHRASE
gpg: encrypted with 2048-bit ELG-E key, ID 140A17F1, created 2009-12-14
"YK-KSM crater Import Key"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] PLAINTEXT 62 1260805257
gpg: Signature made Mon 14 Dec 2009 04:40:57 PM CET using DSA key ID 8B88A11B
[GNUPG:] SIG_ID YGplk8qkUkb75lY0aurb/iS1Oog 2009-12-14 1260805257
[GNUPG:] GOODSIG AE7279678B88A11B YK-KSM crater Import Key
gpg: Good signature from "YK-KSM crater Import Key"
[GNUPG:] VALIDSIG 9B1820A2F02E3C3B84E344F5AE7279678B88A11B 2009-12-14 1260805257 0 4 0 17 2 00 9B1820A2F02E3C3B84E344F5AE7279678B88A11B
[GNUPG:] TRUST_ULTIMATE
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION
encrypted to: 8C73EAF1140A17F1
signed by: 8B88A11B
You need a passphrase to unlock the secret key for
user: "YK-KSM crater Import Key"
2048-bit ELG-E key, ID 140A17F1, created 2009-12-14 (main key ID 8B88A11B)
line: 1,cccccccccccb,d74fbdf6a890,82211e0854e7369e83d941f24761a84e,881ae7bee927,2009-12-14T16:40:57,
serialnr 1 publicName cccccccccccb internalName d74fbdf6a890 aesKey 82211e0854e7369e83d941f24761a84e lockCode 881ae7bee927 created 2009-12-14T16:40:57 accessed eol
line: 2,cccccccccccd,7a5ad1886b70,3091a8048524ab8407ae816457d764e5,8e5ab609e346,2009-12-14T16:40:57,
serialnr 2 publicName cccccccccccd internalName 7a5ad1886b70 aesKey 3091a8048524ab8407ae816457d764e5 lockCode 8e5ab609e346 created 2009-12-14T16:40:57 accessed eol
line: 3,ccccccccccce,981abbbeafb8,91be4bfd2f40e24ebd39386868aa9619,037b6f6ae73c,2009-12-14T16:40:57,
serialnr 3 publicName ccccccccccce internalName 981abbbeafb8 aesKey 91be4bfd2f40e24ebd39386868aa9619 lockCode 037b6f6ae73c created 2009-12-14T16:40:57 accessed eol
line: 4,cccccccccccf,c1f33c17f77b,a2389839d7b80bfe4c80258184aff4ce,abf92cbbdab3,2009-12-14T16:40:57,
serialnr 4 publicName cccccccccccf internalName c1f33c17f77b aesKey a2389839d7b80bfe4c80258184aff4ce lockCode abf92cbbdab3 created 2009-12-14T16:40:57 accessed eol
line: 5,cccccccccccg,c55773192393,7387b5f6bede83f64a9cd75b2023826a,d70c937bbbff,2009-12-14T16:40:57,
serialnr 5 publicName cccccccccccg internalName c55773192393 aesKey 7387b5f6bede83f64a9cd75b2023826a lockCode d70c937bbbff created 2009-12-14T16:40:57 accessed eol
user@ksm:~$
</nowiki>
When importing large data sets it is recommended to avoid the
--verbose flag to reduce noise.
To test the import, you can attempt to decrypt an (invalid) OTP for
one of the AES keys. Like this:
user@ksm:~$ curl 'http://localhost/wsapi/decrypt?otp=cccccccccccdvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv'
ERR Corrupt OTP
user@ksm:~$
In the system log file /var/log/ykksm.log you should get this error:
Dec 14 17:20:08 crater ykksm[12693]: UID error: cccccccccccdvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv a515841f249c5f4bb8e9007ab0f7ac2b: a515841f249c vs 7a5ad1886b70
Note that the actual values may differ slightly because the AES key
you generated was random.

284
doc/Installation.txt Normal file
View File

@ -0,0 +1,284 @@
== Installation and configuration of Yubikey KSM ==
The Yubikey KSM module is responsible for storing AES keys and
providing two interfaces:
* Decrypting an OTP
* Adding new AES keys
It is intentionally not possible to extract the AES keys or to make
modifications to the database content, see [[DesignGoals]].
The installation procedure documented below applies to any Unix-like
environment, although it was written for Debian GNU/Linux version 5.0
(aka "lenny").
Since version 1.1 of the YK-KSM, any database supported by the PHP PDO
interface is supported by the YK-KSM. To give concrete examples, we
will here explain how to set it up using MySQL or PostgreSQL. Note
that you only need to install either MySQL or PostgreSQL (or any other
supported database), not both!
=== Step 1: YK-KSM Installation ===
First you should download and install the latest YK-KSM release:
<nowiki>user@ksm:~$ sudo apt-get install wget make help2man
...
user@ksm:~$ wget http://yubico.github.com/yubikey-ksm/releases/yubikey-ksm-1.8.tgz
...
user@ksm:~$ tar xfz yubikey-ksm-1.8.tgz
user@ksm:~$ cd yubikey-ksm-1.8
user@ksm:~/yubikey-ksm-1.8$ sudo make install
...
user@ksm:~/yubikey-ksm-1.8$</nowiki>
Alternatively, you may also check out YK-KSM from its source code repository. For example:
<nowiki>user@ksm:~$ sudo apt-get install git make help2man
...
user@ksm:~$ git clone git://github.com/Yubico/yubikey-ksm.git
...
user@ksm:~$ cd yubikey-ksm
user@ksm:~/yubikey-ksm$ sudo make install
...
user@ksm:~/yubikey-ksm$</nowiki>
The rest of this documentation will assume you have installed the
YK-KSM with 'make install'.
=== Step 2: Install web server and PHP ===
You will need to install a web server with PHP5 and the PHP mcrypt
interface:
user@ksm:~$ sudo apt-get install apache2 php5 php5-mcrypt
Any web server with PHP support should work.
=== Step 3A: MySQL Installation ===
Install the required packages:
<nowiki>user@ksm:~$ sudo apt-get install mysql-server php5-mysql libdbd-mysql-perl
...
user@ksm:~$</nowiki>
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:
<nowiki>user@ksm:~$ cat > .my.cnf
[client]
user = root
password = YOURPASSWORD
user@ksm:~$</nowiki>
First create the database and the tables as follows:
<nowiki>user@ksm:~$ echo 'create database ykksm' | mysql
user@ksm:~$ mysql ykksm < /usr/share/doc/yubikey-ksm/ykksm-db.sql
user@ksm:~$</nowiki>
You should also create database users for the decrypt and import
interfaces, normally called 'ykksmreader' and 'ykksmimporter':
<nowiki>user@ksm:~$ mysql --silent ykksm
mysql> CREATE USER 'ykksmreader';
mysql> GRANT SELECT ON ykksm.yubikeys TO 'ykksmreader'@'localhost';
mysql> SET PASSWORD FOR 'ykksmreader'@'localhost' = PASSWORD('yourpassword');
mysql> CREATE USER 'ykksmimporter';
mysql> GRANT INSERT ON ykksm.yubikeys TO 'ykksmimporter'@'localhost';
mysql> SET PASSWORD FOR 'ykksmimporter'@'localhost' = PASSWORD('otherpassword');
mysql> FLUSH PRIVILEGES;
mysql> \q
user@ksm:~$</nowiki>
== Step 3B: PostgreSQL Installation ==
Install some packages:
<nowiki>
user@ksm:~$ sudo apt-get install postgresql php5-pgsql libdbd-pg-perl
...
user@ksm:~$
</nowiki>
The database needs to be initialized as follows:
<nowiki>
user@ksm:~$ sudo su postgres
postgres@ksm:~$ createdb ykksm
postgres@ksm:~$ psql ykksm < /usr/share/doc/yubikey-ksm/ykksm-db.sql
postgres@ksm:~$
</nowiki>
You also need to create a user for the decrypt interface, normally
called 'ykksmreader':
<nowiki>
postgres@ksm:~$ psql ykksm -q
ykksm=# CREATE USER ykksmreader PASSWORD 'yourpassword';
ykksm=# GRANT SELECT ON yubikeys TO ykksmreader;
ykksm=# CREATE USER ykksmimporter PASSWORD 'otherpassword';
ykksm=# GRANT INSERT ON yubikeys TO ykksmimporter;
ykksm=# \q
postgres@ksm:~$
</nowiki>
During installation and debugging it may be useful to watch the
database log entries:
<nowiki>
user@ksm:~$ sudo tail -F /var/log/postgresql/postgresql-*-main.log &
</nowiki>
== Step 4: Include path configuration ==
Set the include path by creating a file /etc/php5/conf.d/ykksm.ini
with the following content:
<nowiki>
user@ksm:~$ sudo sh -c 'cat > /etc/php5/conf.d/ykksm.ini'
include_path = "/etc/yubico/ksm:/usr/share/yubikey-ksm"
user@ksm:~$ sudo /etc/init.d/apache2 restart
user@ksm:~$
</nowiki>
The paths are the default, if you installed the YK-KSM in some other
place you need to modify the paths.
== Step 5: Logging ==
The PHP interface uses syslog for logging of incoming requests. The
facility is set in ykksm-config.php but defaults the 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/ykksm.conf with this content:
<nowiki>
user@ksm:~$ sudo sh -c 'cat > /etc/rsyslog.d/ykksm.conf'
local0.* -/var/log/ykksm.log
user@ksm:~$ sudo /etc/init.d/rsyslog restart
...
user@ksm:~$
</nowiki>
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/ykksm like this:
<nowiki>
user@ksm:~$ sudo sh -c 'cat > /etc/logrotate.d/ykksm'
/var/log/ykksm.log {
weekly
missingok
rotate 9999
notifempty
postrotate
invoke-rc.d rsyslog reload > /dev/null
endscript
}
user@ksm:~$
</nowiki>
=== Step 5.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-KSM 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):
<nowiki>
*.*;auth,authpriv.none -/var/log/syslog
*.=info;*.=notice;*.=warn;\
auth,authpriv.none;\
cron,daemon.none;\
mail,news.none -/var/log/messages
</nowiki>
Change them into:
<nowiki>
*.*;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
</nowiki>
== Step 6: Decrypt OTP Interface ==
The interface to decrypt OTPs is implemented using a PHP script. You
can place the script under any URL, but we recommend serving it as
http://ykksm.example.org/wsapi/decrypt. The simplest way is to use
the 'symlink' rule in our makefile:
<nowiki>
user@ksm:~$ sudo make -f /usr/share/doc/yubikey-ksm/ykksm.mk symlink
install -d /var/www/wsapi
ln -sf /usr/share/yubikey-ksm/.htaccess /var/www/wsapi/.htaccess
ln -sf /usr/share/yubikey-ksm/ykksm-decrypt.php /var/www/wsapi/decrypt.php
user@ksm:~$
</nowiki>
You may also run the commands manually.
== Step 7: YK-KSM Configuration ==
You need to edit the ykksm-config.php script. An example file is
included in YK-KSM as 'ykksm-config.php'. It is normally installed as
/etc/yubico/ksm/ykksm-config.php:
<nowiki>
user@ksm:~$ sudo cat /etc/yubico/ksm/ykksm-config.php
<?php
$db_dsn = "mysql:dbname=ykksm;host=127.0.0.1";
$db_username = "ykksmreader";
$db_password = "yourpassword";
$db_options = array();
$logfacility = LOG_LOCAL0;
?>
user@ksm:~$
</nowiki>
Be careful about the user permissions and ownership so that unrelated
users on the system cannot read the database password.
Typically you only need to modify the database password, and possibly
the database definition in $db_dsn. Example DSN for a MySQL setup:
$db_dsn = "mysql:dbname=ykksm;host=127.0.0.1";
An example DSN for a PostgreSQL setup:
$db_dsn = "pgsql:dbname=ykksm;host=127.0.0.1";
=== The End ===
You now have a YK-KSM up and running. You can test the service by
requesting a URL. Using wget, for example:
<nowiki>
user@ksm:~$ sudo apt-get install wget
user@ksm:~$ wget -q -O - 'http://localhost/wsapi/decrypt?otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
ERR Unknown yubikey
user@ksm:~$
</nowiki>
You will need to import keys into the database for the decrypt
function to do anything useful. See [[ServerHardening]] on how to
improve security of your system. Likely next steps are
[[GenerateKSMKey]], [[GenerateKeys]] and/or [[ImportKeysToKSM]].

View File

@ -0,0 +1,99 @@
== Format of Key Provisioning Data = =
This file holds data used in the Yubikey personalization phase.
The file is an OpenPGP signed and encrypted text file. Readers should
support both CRLF and LF line endings. The values are text and
separated by comma ("," ASCII 0x2C). The first line of the file MUST
be as follows:
# ykksm 1
Each of the rest lines in the file follows the following format:
serialNr,publicName,internalName,aesKey,lockCode,created,accessed[,progflags] # comment
Any data after a # is treated as a comment and is ignored. Lines of
the following format:
# comment
are also treated as comments.
The meaning are as follows:
;serialNr:
: the serial number of the device used for the barcode, decimal integer
;publicName:
: encoding of the "external" yubikey prefix, 0-16 modhex characters, typically 12
: modhex encoded data
;internalName:
: encoding of the "internal" yubikey identity, always 6 binary bytes = 12 hex,
: hex encoded data
;aesKey:
: an aes key used for the device, length decides whether it is a 128, 192, or 256 bit keys.
: hex encoded data
;lockCode:
: the locking code, always 6 binary bytes = 12 hex,
: hex encoded data
;created:
: timestamp of when the key was created
: for example 2009-02-24T17:41:57 or empty
;accessed:
: timestamp of when the key was last accessed
: for example 2009-02-24T17:41:57 or empty
;progflags:
: optional field, integer with flags used during personalization
: to enable, e.g., static key mode or cr output
Examples of valid data lines:
<nowiki>
4711,dlcfffckrcde,ca62baca62ba,ecde18dbe76fbd0c33330f1c354871db,be70aeca62ba,2009-01-22 00:25:11,
4712,,ca62baca62ba,ecde18dbe76fbd0c33330f1c354871db,be70aeca62ba,2009-01-22 00:25:11,2009-02-13 00:05:40
4713,dlcfffckrcdedlcf,ca62baca62ba,ecde18dbe76fbd0c33330f1c354871db,be70aeca62ba,2009-01-22 00:25:11,2009-02-13 00:05:40,0
4714,dlcfffckrcdedlcf,ca62baca62ba,ecde18dbe76fbd0c33330f1c354871db,be70aeca62ba,2009-01-22 00:25:11,2009-02-13 00:05:40,4711
</nowiki>
Example of actual data using the password 'foobar' (normally it would
be encrypted to a particular OpenPGP key id):
<nowiki>
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.9 (GNU/Linux)
jA0EAwMClfljrWYVfm5gycDMIpZXLnzKtUfeEsqXRp63IdAghBzAfdIt4aeJ2kdV
x8uvvHKeHfytjEo/U9Wg4NYqYoDnMeb4zXBmrRqWu558ldW75e5R2kPImuQnZIBQ
3WKRbElrLpQTlbdyDDAzlOnVLvTrmekZ8ByUrED3tyZKJw7OW5YsHi3z5N+QNFbZ
hpMWfDBiJRksQEXv3BbiWVojSS+ZlCBiDjqnbIGuk0nZlJSe3F3Jwdz22Y05aU2h
+2e6vWkqsbvZMVHnU6pauyaM1dh2owXsoHCPLM1fs7ztIh5dAnV9d0TuW4ufKEFQ
FdH5c4dNgl36CNM8dDlM3c8YpfjxlQ11e6ub7QZC1Eu3gqvfPIvYpczlwjkYOkcH
nu1Iq42VgUSJzBr36aL9lLySyT8WRizzmJLaGYX/YqKgBXt6RTSO984WsxE6cl80
paFvFOjybJ2V5GYc7pfdZAM2ySEhnS6PaxYAQXfrEhhtTTCCg1eCqKh4Yamv3u0v
DAkppMqXeprjpC4cNvrQsVOKGx7HissA5x4rECLC
=d54w
-----END PGP MESSAGE-----
</nowiki>
=== Naming Scheme ===
The files should use the standard GnuPG output extension '.asc'.
If you want to store many keys in a one-key per file approach, we
suggest to create files named after the serial number. For example:
<nowiki>
0.asc
1.asc
2.asc
3.asc
4.asc
5.asc
6.asc
7.asc
8.asc
9.asc
10.asc
11.asc
...
</nowiki>

31
doc/MakeRelease.txt Normal file
View 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, help2man, git2cl
which can be installed (under Ubuntu) by running:
sudo apt-get install make git gnupg help2man 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-ksm/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.

265
doc/ServerHardening.txt Normal file
View File

@ -0,0 +1,265 @@
== Server Hardening ==
While the defaults should be secure, there are some simple
administrative actions that will increase your overall security. None
of these steps are required, but we encourage you to read this
document to see if the enhancements are relevant for your environment.
=== Tighten PHP configuration ===
Tighten the security of the PHP installation by creating a file
/etc/php5/conf.d/harden.ini with the following content:
<nowiki>
user@host:~$ sudo sh -c 'cat > /etc/php5/conf.d/harden.ini'
display_errors = Off
log_errors = On
user@host:~$
</nowiki>
=== Tighten Apache configuration ===
Tighten the security of the Apache installation by making sure
directory listings are disabled globally. Edit
/etc/apache2/conf.d/security and make sure the following is
uncommented:
<nowiki>
<Directory />
AllowOverride None
Order Deny,Allow
Deny from all
</Directory>
</nowiki>
=== Time synchronization ===
For logging and (on the validation server) time-stamping it is
important to have synchronized clocks. Install ntp.
<nowiki>
user@host:~$ sudo apt-get install ntp
...
</nowiki>
=== Firewall ===
There is no reason why the KSM needs to listen to incoming requests
from the entire Internet, and restricting access to the intended
YK-VAL servers are recommended.
<nowiki>
user@ksm:~$ sudo sh -c 'cat > /etc/network/if-pre-up.d/iptables'
#!/bin/sh
# IPv4 firewall:
iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -p all -j ACCEPT
iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i eth0 -s 1.2.3.4 --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -i eth0 -s 2.3.4.5 --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -i eth0 -s 2.3.4.5 --dport 443 -j ACCEPT
# IPv6 firewall:
ip6tables -F
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT
ip6tables -A INPUT -i lo -p all -j ACCEPT
ip6tables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -p icmpv6 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 -s 2000:1:2::3 --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 -s 2000:2:3::4 --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 -s 2000:2:3::4 --dport 443 -j ACCEPT
user@ksm:~$ chmod +x /etc/network/if-pre-up.d/iptables
user@ksm:~$
</nowiki>
Replace 1.2.3.4 (for IPv4) and 2000:1:2::3 (for IPv6) with the address
of the host you want to be able to login from via SSH, and replace
2.3.4.5 (for IPv4) and 2000:2:3::4 (for IPv6) with the address of the
YK-VAL that will be accessing this YK-KSM. Add more lines for each
validation server and SSH host.
For a validation server, you may want to allow HTTP(S) requests from
anyone, but not anything else.
<nowiki>
user@val:~$ sudo sh -c 'cat > /etc/network/if-pre-up.d/iptables'
#!/bin/sh
# IPv4 firewall
iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -p all -j ACCEPT
iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i eth0 -s 1.2.3.4 --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 443 -j ACCEPT
# IPv6 firewall:
ip6tables -F
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT
ip6tables -A INPUT -i lo -p all -j ACCEPT
ip6tables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -p icmpv6 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 -s 2000:1:2::3 --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 --dport 443 -j ACCEPT
user@ksm:~$ chmod +x /etc/network/if-pre-up.d/iptables
user@ksm:~$
</nowiki>
Again, replace 1.2.3.4 (for IPv4) and 2000:1:2::3 (for IPv6) with the
address of the host you want to be able to login from via SSH.
If you want to allow SSH and HTTP(S) from everywhere, but nothing
else, try this:
<nowiki>
user@val:~$ sudo sh -c 'cat > /etc/network/if-pre-up.d/iptables'
#!/bin/sh
# IPv4 firewall
iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -p all -j ACCEPT
iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 443 -j ACCEPT
# IPv6 firewall:
ip6tables -F
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT
ip6tables -A INPUT -i lo -p all -j ACCEPT
ip6tables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -p icmpv6 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp -i eth0 --dport 443 -j ACCEPT
user@ksm:~$ chmod +x /etc/network/if-pre-up.d/iptables
user@val:~$
</nowiki>
=== Database encryption ===
The database contains sensitive information. If someone is able to
access your machine physically, they may shut it off and steal it with
the goal of reading out the sensitive information. By encrypting the
disk, you can prevent this. Note that this does not protect against
an attacker who has physical access to your server and sufficient time
to read out the data from the already running system.
Full disk encryption will give you the highest protection, but
requires that you can enter the disk encryption password on each
power-up. This can be unpractical when your hosting environment is
remote.
Partial disk encryption allows the operating system to start up, and
enable you to login to the machine remotely to enter the disk
encryption password. This is less secure than full disk encryption,
because an attacker could physically disconnect your machine, modify
the operating system to send a copy of the password to the attacker,
but may be sufficient if you keep good track of when your machine is
not working properly.
To use partial disk encryption for the database content, we suggest
you install the operating system as normal but create another file
system on an encrypted volume.
If you need swap space, be sure to only put the swap on the encrypted
volume too. Make sure that the database does not start up
automatically on boot, and also make sure that the system does not
attempt to mount your encrypted partition automatically.
Setup:
<nowiki>
user@ksm:~$ sudo apt-get install loop-aes-utils loop-aes-modules-2.6-amd64
...
user@ksm:~$ sudo rmmod loop && sudo modprobe loop
user@ksm:~$ sudo dd if=/dev/zero of=/root/ksm.img bs=1k count=1M
...
user@ksm:~$ sudo losetup -e AES128 /dev/loop0 /root/ksm.img
Password:
user@ksm:~$ sudo mkfs.ext2 -q /dev/loop0
user@ksm:~$ sudo mkdir /ksm
user@ksm:~$ sudo mount /dev/loop0 /ksm
user@ksm:~$ sudo /etc/init.d/postgresql-8.3 stop
...
user@ksm:~$ sudo update-rc.d -f postgresql-8.3 remove
user@ksm:~$ sudo mv /var/lib/postgresql /ksm
user@ksm:~$ sudo ln -s /ksm/postgresql /var/lib/postgresql
user@ksm:~$ sudo sh -c 'cat > /usr/local/sbin/ykksm-start'
#!/bin/sh
set -e
set -x
losetup -e AES128 /dev/loop0 /root/ksm.img
fsck /dev/loop0
mount /dev/loop0 /ksm/
/etc/init.d/postgresql-8.3 start
user@ksm:~$ sudo sh -c 'cat > /usr/local/sbin/ykksm-stop'
#!/bin/sh
set -e
set -x
/etc/init.d/postgresql-8.3 stop
umount /ksm
losetup -d /dev/loop0
user@ksm:~$ sudo chmod +x /usr/local/sbin/ykksm-{start,stop}
</nowiki>
Slightly adapted for MySQL:
<nowiki>
user@ksm:~$ sudo apt-get install loop-aes-utils loop-aes-modules-2.6-686
...
user@ksm:~$ sudo rmmod loop && sudo modprobe loop
user@ksm:~$ sudo dd if=/dev/zero of=/root/ksm.img bs=1k count=1M
...
user@ksm:~$ sudo losetup -e AES128 /dev/loop0 /root/ksm.img
Password:
user@ksm:~$ sudo mkfs.ext2 -q /dev/loop0
user@ksm:~$ sudo mkdir /ksm
user@ksm:~$ sudo mount /dev/loop0 /ksm
user@ksm:~$ sudo /etc/init.d/mysql stop
user@ksm:~$ sudo update-rc.d -f mysql remove
user@ksm:~$ sudo mv /var/lib/mysql /ksm
user@ksm:~$ sudo ln -s /ksm/mysql /var/lib/mysql
user@ksm:~$ sudo sh -c 'cat > /usr/local/sbin/ykksm-start'
#!/bin/sh
set -e
set -x
losetup -e AES128 /dev/loop0 /root/ksm.img
fsck /dev/loop0
mount /dev/loop0 /ksm/
/etc/init.d/mysql start
user@ksm:~$ sudo sh -c 'cat > /usr/local/sbin/ykksm-stop'
#!/bin/sh
set -e
set -x
/etc/init.d/mysql stop
umount /ksm
losetup -d /dev/loop0
user@ksm:~$ sudo chmod +x /usr/local/sbin/ykksm-{start,stop}
</nowiki>
Then in the future, to start the YK-KSM, you will need to login to the
machine and issue the command 'sudo ykksm-start' and enter the disk
encryption password.
Again, make sure that you don't use any unencrypted swap.
=== Intrusion detection ===
To make some attacks discussed in the previous section harder, make
sure that your system has a hardware intrusion detection system and
that your software is notified when it is triggered. When the
intrusion detection is triggered, you should stop the database and
unmount the encrypted volume and send out a signal to your
administrators.

48
doc/SyncMonitor.txt Normal file
View File

@ -0,0 +1,48 @@
== YK-KSM Synchronization Monitor ==
If you deploy multiple redundant YK-KSM 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 'ykksm-checksum' script 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 serial number, public name, internal name
and AES key.
Sample output looks like this, first there is a Unix time (for
freshness) and then is the truncated hash value.
<nowiki>
1284488221
50f5649b80
</nowiki>
The script requires the Perl SHA-1 package. Install it like this:
<nowiki>
user@ksm:~$ sudo apt-get install libdigest-sha1-perl
...
user@ksm:~$
</nowiki>
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. The intention is that you run a check
that downloads this file from all of your KSMs, and the Nagios check
verify that all values are 1) fresh (Unix time is not too old) and 2)
that the truncated hash value is identical on all KSMs.
<nowiki>
user@ksm:~$ sudo sh -c 'cat > /etc/cron.hourly/run-ykksm-checksum'
#!/bin/sh
FILE=/var/www/checksum.txt
(date --utc +%s; ykksm-checksum --db-user ykksmreader --db-passwd `grep password /etc/yubico/ksm/ykksm-config.php|cut -d\ -f3|cut -d\" -f2`) > $FILE.tmp
mv $FILE.tmp $FILE
user@ksm:~$ sudo chmod +x /etc/cron.hourly/run-ykksm-checksum
</nowiki>
If you notice mismatches, you may want to run ykksm-checksum 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.