diff --git a/doc/DecryptionProtocol.txt b/doc/DecryptionProtocol.txt new file mode 100644 index 0000000..a7f650a --- /dev/null +++ b/doc/DecryptionProtocol.txt @@ -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. diff --git a/doc/DesignGoals.txt b/doc/DesignGoals.txt new file mode 100644 index 0000000..062398d --- /dev/null +++ b/doc/DesignGoals.txt @@ -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 diff --git a/doc/GenerateKSMKey.txt b/doc/GenerateKSMKey.txt new file mode 100644 index 0000000..d0976a2 --- /dev/null +++ b/doc/GenerateKSMKey.txt @@ -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 + = key expires in n days + w = key expires in n weeks + m = key expires in n months + 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) " + + 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:~$ \ No newline at end of file diff --git a/doc/GenerateKeys.txt b/doc/GenerateKeys.txt new file mode 100644 index 0000000..1a42388 --- /dev/null +++ b/doc/GenerateKeys.txt @@ -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: + + 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:~$ + +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: + + + #!/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 diff --git a/doc/ImportKeysToKSM.txt b/doc/ImportKeysToKSM.txt new file mode 100644 index 0000000..b24085b --- /dev/null +++ b/doc/ImportKeysToKSM.txt @@ -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: + + + + 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:~$ + + +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. diff --git a/doc/Installation.txt b/doc/Installation.txt new file mode 100644 index 0000000..88f9493 --- /dev/null +++ b/doc/Installation.txt @@ -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: + + 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$ + +Alternatively, you may also check out YK-KSM from its source code repository. For example: + + 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$ + +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: + + user@ksm:~$ sudo apt-get install mysql-server php5-mysql libdbd-mysql-perl + ... + user@ksm:~$ + +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: + + user@ksm:~$ cat > .my.cnf + [client] + user = root + password = YOURPASSWORD + user@ksm:~$ + +First create the database and the tables as follows: + + user@ksm:~$ echo 'create database ykksm' | mysql + user@ksm:~$ mysql ykksm < /usr/share/doc/yubikey-ksm/ykksm-db.sql + user@ksm:~$ + +You should also create database users for the decrypt and import +interfaces, normally called 'ykksmreader' and 'ykksmimporter': + + 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:~$ + +== Step 3B: PostgreSQL Installation == + +Install some packages: + + + user@ksm:~$ sudo apt-get install postgresql php5-pgsql libdbd-pg-perl + ... + user@ksm:~$ + + +The database needs to be initialized as follows: + + + user@ksm:~$ sudo su postgres + postgres@ksm:~$ createdb ykksm + postgres@ksm:~$ psql ykksm < /usr/share/doc/yubikey-ksm/ykksm-db.sql + postgres@ksm:~$ + + +You also need to create a user for the decrypt interface, normally +called 'ykksmreader': + + + 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:~$ + + +During installation and debugging it may be useful to watch the +database log entries: + + + user@ksm:~$ sudo tail -F /var/log/postgresql/postgresql-*-main.log & + + +== Step 4: Include path configuration == + +Set the include path by creating a file /etc/php5/conf.d/ykksm.ini +with the following content: + + + 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:~$ + + +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: + + + 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:~$ + + +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: + + + 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:~$ + + +=== 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): + + + *.*;auth,authpriv.none -/var/log/syslog + *.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + + +Change them into: + + + *.*;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 + + +== 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: + + + 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:~$ + + +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: + + + user@ksm:~$ sudo cat /etc/yubico/ksm/ykksm-config.php + + user@ksm:~$ + + +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: + + + user@ksm:~$ sudo apt-get install wget + user@ksm:~$ wget -q -O - 'http://localhost/wsapi/decrypt?otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh' + ERR Unknown yubikey + user@ksm:~$ + + +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]]. diff --git a/doc/KeyProvisioningFormat.txt b/doc/KeyProvisioningFormat.txt new file mode 100644 index 0000000..bcec9b2 --- /dev/null +++ b/doc/KeyProvisioningFormat.txt @@ -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: + + + 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 + + +Example of actual data using the password 'foobar' (normally it would +be encrypted to a particular OpenPGP key id): + + + -----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----- + + +=== 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: + + + 0.asc + 1.asc + 2.asc + 3.asc + 4.asc + 5.asc + 6.asc + 7.asc + 8.asc + 9.asc + 10.asc + 11.asc + ... + diff --git a/doc/MakeRelease.txt b/doc/MakeRelease.txt new file mode 100644 index 0000000..693e358 --- /dev/null +++ b/doc/MakeRelease.txt @@ -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. diff --git a/doc/ServerHardening.txt b/doc/ServerHardening.txt new file mode 100644 index 0000000..eb437f3 --- /dev/null +++ b/doc/ServerHardening.txt @@ -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: + + + user@host:~$ sudo sh -c 'cat > /etc/php5/conf.d/harden.ini' + display_errors = Off + log_errors = On + user@host:~$ + + +=== 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: + + + + AllowOverride None + Order Deny,Allow + Deny from all + + + +=== Time synchronization === + +For logging and (on the validation server) time-stamping it is +important to have synchronized clocks. Install ntp. + + + user@host:~$ sudo apt-get install ntp + ... + + +=== 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. + + + 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:~$ + + +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. + + + 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:~$ + + +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: + + + 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:~$ + + +=== 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: + + + 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} + + +Slightly adapted for MySQL: + + + 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} + + +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. diff --git a/doc/SyncMonitor.txt b/doc/SyncMonitor.txt new file mode 100644 index 0000000..99aa929 --- /dev/null +++ b/doc/SyncMonitor.txt @@ -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. + + + 1284488221 + 50f5649b80 + + +The script requires the Perl SHA-1 package. Install it like this: + + + user@ksm:~$ sudo apt-get install libdigest-sha1-perl + ... + user@ksm:~$ + + +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. + + + 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 + + +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.