yubikey-ksm-1.15/0000755000175000017500000000000012412604401012017 5ustar jasjasyubikey-ksm-1.15/ykksm-export0000755000175000017500000000744012412604401014427 0ustar jasjas#!/usr/bin/perl # Written by Simon Josefsson . # Copyright (c) 2009-2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use DBI; use MIME::Base64; sub usage { print "Usage: $0 [--verbose] [--help] [--database DBI] [--db-user USER] [--db-passwd PASSWD]\n"; print "\n"; print "Tool to export keys to the YKKSM-KEYPROV format.\n"; print "\n"; print " --database DBI: Database identifier, see http://dbi.perl.org/\n"; print " defaults to a MySQL database ykksm on localhost,\n"; print " i.e., DBI::mysql:ykksm.\n"; print "\n"; print " --db-user USER: Database username to use, defaults to empty string.\n"; print "\n"; print " --db-passwd PASSWD: Database password to use, defaults to empty string.\n"; print "\n"; print "Usage example:\n"; print "\n"; print " ./ykksm-export --db-user foo --db-passwd pass123 |\n"; print " gpg -a --sign --encrypt -r 1D2F473E > keys.txt\n"; print "\n"; exit 1; } #Support dbconfig-common generated database settings, if available our ($dbuser, $dbpass, $basepath, $dbname, $dbserver, $dbport, $dbtype); if( -r '/etc/yubico/ksm/config-db.cfg' ) { require '/etc/yubico/ksm/config-db.cfg'; } else { $dbtype = 'mysql'; $dbname = 'ykksm'; } my $verbose = 0; my $db = "dbi:$dbtype:$dbname"; while ($ARGV[0] =~ m/^-(.*)/) { my $cmd = shift @ARGV; if (($cmd eq "-v") || ($cmd eq "--verbose")) { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq "--database") { $db = shift; } elsif ($cmd eq "--db-user") { $dbuser = shift; } elsif ($cmd eq "--db-passwd") { $dbpass = shift; } } if ($#ARGV>=0) { usage(); } my $dbh = DBI->connect($db, $dbuser, $dbpass, {'RaiseError' => 1}); my $sth = $dbh->prepare ('SELECT serialnr, publicname, internalname, aeskey, lockcode, created FROM yubikeys') or die "Couldn't prepare statement: " . $dbh->errstr; $sth->execute() or die "Couldn't execute statement: " . $sth->errstr; my $row; while ($row = $sth->fetchrow_hashref()) { if ($verbose) { print "# "; foreach my $key (keys %$row) { print $key . "=" . $row->{$key} . " "; } print "\n"; } print $row->{'serialnr'} . ","; print $row->{'publicname'} . ","; print $row->{'internalname'} . ","; print $row->{'aeskey'} . ","; print $row->{'lockcode'} . ","; print $row->{'created'} . ",\n"; } if ($sth->rows == 0) { print "No data?!\n\n"; } $sth->finish; $dbh->disconnect(); exit 0; yubikey-ksm-1.15/Makefile0000644000175000017500000001160412412604401013461 0ustar jasjas# Written by Simon Josefsson . # Copyright (c) 2009-2014 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. VERSION = 1.15 PACKAGE = yubikey-ksm CODE = .htaccess Makefile NEWS README ykksm-config.php ykksm-db.sql \ ykksm-decrypt.php ykksm-export ykksm-gen-keys \ ykksm-import ykksm-utils.php ykksm-checksum DOCS = doc/DecryptionProtocol.txt doc/DesignGoals.txt \ doc/GenerateKeys.txt doc/GenerateKSMKey.txt \ doc/ImportKeysToKSM.txt doc/Installation.txt \ doc/KeyProvisioningFormat.txt doc/ServerHardening.txt \ doc/SyncMonitor.txt MANS = ykksm-checksum.1 ykksm-export.1 ykksm-gen-keys.1 \ ykksm-import.1 all: @echo "Try 'make install' or 'make symlink'." @echo "See doc/Installation.txt for more information" @exit 1 # Installation rules. etcprefix = /etc/yubico/ksm binprefix = /usr/bin phpprefix = /usr/share/yubikey-ksm docprefix = /usr/share/doc/yubikey-ksm manprefix = /usr/share/man/man1 wwwgroup = www-data install: $(MANS) install -D --mode 640 .htaccess $(DESTDIR)$(phpprefix)/.htaccess install -D --mode 640 ykksm-decrypt.php $(DESTDIR)$(phpprefix)/ykksm-decrypt.php install -D --mode 640 ykksm-utils.php $(DESTDIR)$(phpprefix)/ykksm-utils.php install -D ykksm-gen-keys $(DESTDIR)$(binprefix)/ykksm-gen-keys install -D ykksm-import $(DESTDIR)$(binprefix)/ykksm-import install -D ykksm-export $(DESTDIR)$(binprefix)/ykksm-export install -D ykksm-checksum $(DESTDIR)$(binprefix)/ykksm-checksum install -D --backup --mode 640 --group $(wwwgroup) ykksm-config.php $(DESTDIR)$(etcprefix)/ykksm-config.php install -D ykksm-gen-keys.1 $(DESTDIR)$(manprefix)/ykksm-gen-keys.1 install -D ykksm-import.1 $(DESTDIR)$(manprefix)/ykksm-import.1 install -D ykksm-export.1 $(DESTDIR)$(manprefix)/ykksm-export.1 install -D ykksm-checksum.1 $(DESTDIR)$(manprefix)/ykksm-checksum.1 install -D ykksm-db.sql $(DESTDIR)$(docprefix)/ykksm-db.sql install -D Makefile $(DESTDIR)$(docprefix)/ykksm.mk install -D $(DOCS) $(DESTDIR)$(docprefix)/ wwwprefix = /var/www/wsapi symlink: install -d $(wwwprefix) ln -sf $(phpprefix)/.htaccess $(wwwprefix)/.htaccess ln -sf $(phpprefix)/ykksm-decrypt.php $(wwwprefix)/decrypt.php # Maintainer rules. PROJECT = $(PACKAGE) $(PACKAGE)-$(VERSION).tgz: $(FILES) $(MANS) mkdir $(PACKAGE)-$(VERSION) $(PACKAGE)-$(VERSION)/doc cp $(CODE) $(PACKAGE)-$(VERSION)/ cp $(MANS) $(PACKAGE)-$(VERSION)/ cp $(DOCS) $(PACKAGE)-$(VERSION)/doc/ git2cl > $(PACKAGE)-$(VERSION)/ChangeLog tar cfz $(PACKAGE)-$(VERSION).tgz $(PACKAGE)-$(VERSION) rm -rf $(PACKAGE)-$(VERSION) dist: $(PACKAGE)-$(VERSION).tgz distclean: clean rm -f *.1 clean: rm -f *~ rm -rf $(PACKAGE)-$(VERSION) NAME_ykksm-checksum = 'Print checksum of important database fields. Useful for quickly determining whether several KSMs are in sync.' NAME_ykksm-export = 'Tool to export keys to the YKKSM-KEYPROV format.' NAME_ykksm-gen-keys = 'Tool to generate keys on the YKKSM-KEYPROV format.' NAME_ykksm-import = 'Tool to import key data on the YKKSM-KEYPROV format.' %.1: % help2man -N --name=$(NAME_$*) --version-string=1 ./$* > $@ man: $(MANS) release: dist @head -1 NEWS | grep -q "Version $(VERSION) (released `date -I`)" || \ (echo 'error: You need to update date/version in NEWS'; exit 1) @if test ! -d "$(YUBICO_WWW_REPO)"; then \ echo "yubico www repo not found!"; \ echo "Make sure that YUBICO_WWW_REPO is set"; \ exit 1; \ fi gpg --detach-sign $(PACKAGE)-$(VERSION).tgz gpg --verify $(PACKAGE)-$(VERSION).tgz.sig git tag -s -m "$(PACKAGE) $(VERSION)" $(PACKAGE)-$(VERSION) $(YUBICO_WWW_REPO)/publish $(PROJECT) $(VERSION) $(PACKAGE)-$(VERSION).tgz* @echo "Release created and tagged, remember to git push && git push --tags" yubikey-ksm-1.15/ykksm-decrypt.php0000644000175000017500000001071512412604401015342 0ustar jasjas. # Copyright (c) 2009-2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require_once 'ykksm-config.php'; require_once 'ykksm-utils.php'; openlog("ykksm", LOG_PID, $logfacility) or die("ERR Syslog open error\n"); $otp = $_REQUEST["otp"]; if (!$otp) { syslog(LOG_INFO, "No OTP provided"); die("ERR No OTP provided\n"); } if (!preg_match("/^([cbdefghijklnrtuv]{0,16})([cbdefghijklnrtuv]{32})$/", $otp, $matches)) { syslog(LOG_INFO, "Invalid OTP format: $otp"); die("ERR Invalid OTP format\n"); } $id = $matches[1]; $modhex_ciphertext = $matches[2]; # Oracle support in PDO is highly experimental, OCI is used instead # Unfortunately PDO and OCI APIs are different... $use_oci = substr($db_dsn,0,3) === 'oci'; if (!$use_oci) { try { $dbh = new PDO($db_dsn, $db_username, $db_password, $db_options); } catch (PDOException $e) { syslog(LOG_ERR, "Database error: " . $e->getMessage()); die("ERR Database error\n"); } } else { # "oci:" prefix needs to be removed before passing db_dsn to OCI $db_dsn = substr($db_dsn, 4); $dbh = oci_connect($db_username, $db_password, $db_dsn); if (!$dbh) { $error = oci_error(); syslog(LOG_err, "Database error: " . $error["message"]); die("ERR Database error\n"); } } $sql = "SELECT aeskey, internalname FROM yubikeys " . "WHERE publicname = '$id' AND "; if (!$use_oci) { $sql .= "(active OR active = 'true')"; $result = $dbh->query($sql); if (!$result) { syslog(LOG_ERR, "Database query error. Query: " . $sql . " Error: " . print_r ($dbh->errorInfo (), true)); die("ERR Database error\n"); } $row = $result->fetch(PDO::FETCH_ASSOC); $aeskey = $row['aeskey']; $internalname = $row['internalname']; } else { $sql .= "active = 1"; $result = oci_parse($dbh, $sql); $execute = oci_execute($result); if (!$execute) { $error = oci_error($result); syslog(LOG_ERR, 'Database query error. Query: ' . $sql . 'Error: CODE : ' . $error["code"] . ' MESSAGE : ' . $error["message"] . ' POSITION : ' . $error["offset"] . ' STATEMENT : ' . $error["sqltext"]); die("ERR Database error\n"); } $row = oci_fetch_array($result, OCI_ASSOC); $aeskey = $row['AESKEY']; $internalname = $row['INTERNALNAME']; } if (!$aeskey) { syslog(LOG_INFO, "Unknown yubikey: " . $otp); die("ERR Unknown yubikey\n"); } $ciphertext = modhex2hex($modhex_ciphertext); $plaintext = aes128ecb_decrypt($aeskey, $ciphertext); $uid = substr($plaintext, 0, 12); if (strcmp($uid, $internalname) != 0) { syslog(LOG_ERR, "UID error: $otp $plaintext: $uid vs $internalname"); die("ERR Corrupt OTP\n");; } if (!crc_is_good($plaintext)) { syslog(LOG_ERR, "CRC error: $otp: $plaintext"); die("ERR Corrupt OTP\n"); } # Mask out interesting fields $counter = substr($plaintext, 14, 2) . substr($plaintext, 12, 2); $low = substr($plaintext, 18, 2) . substr($plaintext, 16, 2); $high = substr($plaintext, 20, 2); $use = substr($plaintext, 22, 2); $out = "OK counter=$counter low=$low high=$high use=$use"; syslog(LOG_INFO, "SUCCESS OTP $otp PT $plaintext $out") or die("ERR Log error\n"); print "$out\n"; # Close database connection. $dbh = null; ?> yubikey-ksm-1.15/.htaccess0000644000175000017500000000007712412604401013621 0ustar jasjasRewriteEngine on RewriteRule ^([^/\.\?]+)(\?.*)?$ $1.php$2 [L] yubikey-ksm-1.15/doc/0000755000175000017500000000000012412604401012564 5ustar jasjasyubikey-ksm-1.15/doc/ImportKeysToKSM.txt0000644000175000017500000000765512412604401016326 0ustar jasjasImport 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. yubikey-ksm-1.15/doc/GenerateKeys.txt0000644000175000017500000000553012412604401015716 0ustar jasjasGenerate 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 yubikey-ksm-1.15/doc/KeyProvisioningFormat.txt0000644000175000017500000000606712412604401017646 0ustar jasjasKey Provisioning Data Format ---------------------------- 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 ... yubikey-ksm-1.15/doc/ServerHardening.txt0000644000175000017500000002163012412604401016415 0ustar jasjasServer 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. yubikey-ksm-1.15/doc/Installation.txt0000644000175000017500000002067412412604401015777 0ustar jasjasInstallation 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]]. yubikey-ksm-1.15/doc/SyncMonitor.txt0000644000175000017500000000346412412604401015620 0ustar jasjasYK-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 passwo rd /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. yubikey-ksm-1.15/doc/DesignGoals.txt0000644000175000017500000000045512412604401015530 0ustar jasjasYK-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 yubikey-ksm-1.15/doc/GenerateKSMKey.txt0000644000175000017500000000566512412604401016117 0ustar jasjasGenerate 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:~$ yubikey-ksm-1.15/doc/DecryptionProtocol.txt0000644000175000017500000000164312412604401017173 0ustar jasjasYubikey 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. yubikey-ksm-1.15/ykksm-gen-keys.10000644000175000017500000000167612412604401014771 0ustar jasjas.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.3. .TH YKKSM-GEN-KEYS "1" "September 2014" "ykksm-gen-keys 1" "User Commands" .SH NAME ykksm-gen-keys \- Tool to generate keys on the YKKSM-KEYPROV format. .SH SYNOPSIS .B ykksm-gen-keys [\fI\,--verbose\/\fR] [\fI\,--help\/\fR] [\fI\,--urandom\/\fR] [\fI\,--progflags PROGFLAGS\/\fR] [\fI\,--pskc\/\fR] \fI\,START \/\fR[\fI\,END\/\fR] .SH DESCRIPTION Tool to generate keys on the YKKSM\-KEYPROV format. .PP START: Decimal start point. .PP END: Decimal end point, if absent START is used as END. .TP \fB\-\-urandom\fR: Use \fI\,/dev/urandom\/\fP instead of \fI\,/dev/random\/\fP as entropy source. .HP \fB\-\-progflags\fR PROGFLAGS: Add a final personalization configuration string. .HP \fB\-\-pskc\fR: Output keys on the YubiKey PSKC format. .PP Usage example: .IP \&./ykksm\-gen\-keys \fB\-\-urandom\fR 1 10 | .IP gpg \fB\-a\fR \fB\-\-sign\fR \fB\-\-encrypt\fR \fB\-r\fR 1D2F473E > keys.txt yubikey-ksm-1.15/ykksm-import0000755000175000017500000001242512412604401014417 0ustar jasjas#!/usr/bin/perl # Written by Simon Josefsson . # Copyright (c) 2009-2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use DBI; use POSIX qw(strftime); sub usage { print "Usage: $0 [--verbose] [--help] [--database DBI] [--db-user USER] [--db-passwd PASSWD] [--creator CREATOR]\n"; print "\n"; print "Tool to import key data on the YKKSM-KEYPROV format.\n"; print "\n"; print " --database DBI: Database identifier, see http://dbi.perl.org/\n"; print " defaults to a MySQL database ykksm on localhost,\n"; print " i.e., dbi:mysql:ykksm. For PostgreSQL on the local\n"; print " host you can use 'DBI:Pg:dbname=ykksm;host=127.0.0.1'.\n"; print "\n"; print " --db-user USER: Database username to use, defaults to empty string.\n"; print "\n"; print " --db-passwd PASSWD: Database password to use, defaults to empty string.\n"; print "\n"; print " --creator CREATOR: Short string with creator info.\n"; print " Defaults to using the PGP signer key id, normally.\n"; print " you don't change this.\n"; print "\n"; print "Usage example:\n"; print "\n"; print " ./ykksm-import < keys.txt\n"; print "\n"; exit 1; } #Support dbconfig-common generated database settings, if available our ($dbuser, $dbpass, $basepath, $dbname, $dbserver, $dbport, $dbtype); if( -r '/etc/yubico/ksm/config-db.cfg' ) { require '/etc/yubico/ksm/config-db.cfg'; } else { $dbtype = 'mysql'; $dbname = 'ykksm'; } my $verbose = 0; my $creator; my $db = "dbi:$dbtype:$dbname"; while ($ARGV[0] =~ m/^-(.*)/) { my $cmd = shift @ARGV; if (($cmd eq "-v") || ($cmd eq "--verbose")) { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq "--creator") { $creator = shift; } elsif ($cmd eq "--database") { $db = shift; } elsif ($cmd eq "--db-user") { $dbuser = shift; } elsif ($cmd eq "--db-passwd") { $dbpass = shift; } } if ($#ARGV>=0) { usage(); } my $infilename = "tmp.$$"; my $verify_status; my $encrypted_to; my $signed_by; # Read input into temporary file. open TMPFILE, ">$infilename" or die "Cannot open $infilename for writing"; while (<>) { print TMPFILE $_; } close TMPFILE; END { unlink $infilename; } # Get status open(GPGV, "gpg --status-fd 1 --output /dev/null < $infilename 2>&1 |") or die "Cannot launch gpg"; while () { $verify_status .= $_; $encrypted_to = $1 if m,^\[GNUPG:\] ENC_TO ([0-9A-F]+) ,; $signed_by = $1 if m,^\[GNUPG:\] VALIDSIG [0-9A-F]+([0-9A-F]{8}) ,; } close GPGV; print "Verification output:\n" . $verify_status; print "encrypted to: " . $encrypted_to . "\n"; print "signed by: " . $signed_by . "\n"; die "Input not signed?" if !$signed_by; my $dbh = DBI->connect($db, $dbuser, $dbpass, {'RaiseError' => 1}); my $inserth = $dbh->prepare_cached(qq{ INSERT INTO yubikeys (creator, created, serialnr, publicname, internalname, aeskey, lockcode) VALUES (?, ?, ?, ?, ?, ?, ?) }); my $now = strftime "%Y-%m-%dT%H:%M:%S", localtime; $creator = $signed_by if !$creator; open(GPGV, "gpg < $infilename 2>/dev/null |") or die "Cannot launch gpg"; while () { next if m:^#:; my ($serialnr, $publicname, $internalname, $aeskey, $lockcode, $created, $accessed) = m%^([0-9]+),([cbdefghijklnrtuv]+),([0-9a-f]+),([0-9a-f]+),([0-9a-f]+),([T:0-9 -]*),([T:0-9 -]*)%; if ($verbose) { print "line: $_"; } print "\tserialnr $serialnr publicname $publicname " . "internalname $internalname aeskey $aeskey lockcode $lockcode " . "created $created accessed $accessed eol"; if ($verbose) { print "\n"; } else { print "\r"; } $created = $now if !$created; $accessed = "NULL" if !$accessed; $inserth->execute($creator, $created, $serialnr, $publicname, $internalname, $aeskey, $lockcode) or die "Database insert error: " . $dbh->errstr; } print "\n"; close GPGV; $dbh->disconnect(); exit 0; yubikey-ksm-1.15/ykksm-config.php0000644000175000017500000000075312412604401015136 0ustar jasjas yubikey-ksm-1.15/ykksm-utils.php0000644000175000017500000000457412412604401015036 0ustar jasjas. # Copyright (c) 2009-2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. function yubi_hex2bin($h) { if (!is_string($h)) return null; $r=''; for ($a=0; $a> 1; if ($n != 0) { $crc = $crc ^ 0x8408; } } } return $crc; } function crc_is_good($token) { $crc = calculate_crc($token); return $crc == 0xf0b8; } ?> yubikey-ksm-1.15/ykksm-db.sql0000644000175000017500000000073712412604401014270 0ustar jasjascreate table yubikeys ( -- identities: serialnr int not null, publicname varchar(16) unique not null, -- timestamps: created varchar(24) not null, -- the data: internalname varchar(12) not null, aeskey varchar(32) not null, lockcode varchar(12) not null, -- key creator, typically pgp key id of key generator creator varchar(8) not null, -- various flags: active boolean default true, hardware boolean default true, primary key (publicname) ); yubikey-ksm-1.15/README0000644000175000017500000000127612412604401012705 0ustar jasjasYubiKey Key Storage Module (YK-KSM) =================================== The YubiKey Key Storage Module (YK-KSM) provides a AES key storage facility for use with a YubiKey validation server. The YK-KSM is intended to be run on a locked-down server. This separation allows third parties to keep tight control of the AES keys for their YubiKeys, but at the same time allow external validation servers (e.g., Yubico's) to validate OTPs from these YubiKeys. The YK-KSM was designed to work with the YubiKey validation server: https://developers.yubico.com/yubikey-val/ Documentation is in doc/. Development ----------- To create a tarball you must have a recent versions of "help2man" and "git2cl". yubikey-ksm-1.15/ykksm-checksum0000755000175000017500000000776112412604401014716 0ustar jasjas#!/usr/bin/perl # Written by Simon Josefsson . # Copyright (c) 2010-2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use DBI; use POSIX qw(strftime); use Digest::SHA; sub usage { print "Usage: $0 [--verbose] [--help] [--database DBI] [--db-user USER] [--db-passwd PASSWD]\n"; print "\n"; print "Print checksum of important database fields. Useful for quickly\n"; print "determining whether several KSMs are in sync.\n"; print "\n"; print " --database DBI: Database identifier, see http://dbi.perl.org/\n"; print " defaults to a MySQL database ykksm on localhost,\n"; print " i.e., dbi:mysql:ykksm. For PostgreSQL on the local\n"; print " host you can use 'DBI:Pg:dbname=ykksm;host=127.0.0.1'.\n"; print "\n"; print " --db-user USER: Database username to use, defaults to empty string.\n"; print "\n"; print " --db-passwd PASSWD: Database password to use, defaults to empty string.\n"; print "\n"; print "Usage example:\n"; print "\n"; print " ./ykksm-checksum --database dbi:mysql:ykksm --db-user user --db-passwd pencil\n"; print "\n"; exit 1; } #Support dbconfig-common generated database settings, if available our ($dbuser, $dbpass, $basepath, $dbname, $dbserver, $dbport, $dbtype); if( -r '/etc/yubico/ksm/config-db.cfg' ) { require '/etc/yubico/ksm/config-db.cfg'; } else { $dbtype = 'mysql'; $dbname = 'ykksm'; } my $verbose = 0; my $db = "dbi:$dbtype:$dbname"; while ($ARGV[0] =~ m/^-(.*)/) { my $cmd = shift @ARGV; if (($cmd eq "-v") || ($cmd eq "--verbose")) { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq "--database") { $db = shift; } elsif ($cmd eq "--db-user") { $dbuser = shift; } elsif ($cmd eq "--db-passwd") { $dbpass = shift; } } if ($#ARGV>=0) { usage(); } my $dbh = DBI->connect($db, $dbuser, $dbpass, {'RaiseError' => 1}); my $sth = $dbh->prepare ('SELECT serialnr, publicname, internalname, aeskey '. 'FROM yubikeys '. 'ORDER BY serialnr, publicname') or die "Couldn't prepare statement: " . $dbh->errstr; $sth->execute() or die "Couldn't execute statement: " . $sth->errstr; my $sha1 = Digest::SHA->new(1); my $row; while ($row = $sth->fetchrow_hashref()) { if ($verbose) { print "# serialnr=" . $row->{'serialnr'} . " publicname=" . $row->{'publicname'} . "\n"; } $sha1->add($row->{'serialnr'}); $sha1->add($row->{'publicname'}); $sha1->add($row->{'internalname'}); $sha1->add($row->{'aeskey'}); } if ($sth->rows == 0) { print "No data?!\n\n"; exit 1; } print substr ($sha1->hexdigest, 0, 10) . "\n"; $sth->finish; $dbh->disconnect(); exit 0; yubikey-ksm-1.15/ykksm-export.10000644000175000017500000000163612412604401014564 0ustar jasjas.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.3. .TH YKKSM-EXPORT "1" "September 2014" "ykksm-export 1" "User Commands" .SH NAME ykksm-export \- Tool to export keys to the YKKSM-KEYPROV format. .SH SYNOPSIS .B ykksm-export [\fI\,--verbose\/\fR] [\fI\,--help\/\fR] [\fI\,--database DBI\/\fR] [\fI\,--db-user USER\/\fR] [\fI\,--db-passwd PASSWD\/\fR] .SH DESCRIPTION Tool to export keys to the YKKSM\-KEYPROV format. .HP \fB\-\-database\fR DBI: Database identifier, see http://dbi.perl.org/ .IP defaults to a MySQL database ykksm on localhost, i.e., DBI::mysql:ykksm. .HP \fB\-\-db\-user\fR USER: Database username to use, defaults to empty string. .HP \fB\-\-db\-passwd\fR PASSWD: Database password to use, defaults to empty string. .PP Usage example: .IP \&./ykksm\-export \fB\-\-db\-user\fR foo \fB\-\-db\-passwd\fR pass123 | .IP gpg \fB\-a\fR \fB\-\-sign\fR \fB\-\-encrypt\fR \fB\-r\fR 1D2F473E > keys.txt yubikey-ksm-1.15/ykksm-checksum.10000644000175000017500000000210612412604401015036 0ustar jasjas.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.3. .TH YKKSM-CHECKSUM "1" "September 2014" "ykksm-checksum 1" "User Commands" .SH NAME ykksm-checksum \- Print checksum of important database fields. Useful for quickly determining whether several KSMs are in sync. .SH SYNOPSIS .B ykksm-checksum [\fI\,--verbose\/\fR] [\fI\,--help\/\fR] [\fI\,--database DBI\/\fR] [\fI\,--db-user USER\/\fR] [\fI\,--db-passwd PASSWD\/\fR] .SH DESCRIPTION Print checksum of important database fields. Useful for quickly determining whether several KSMs are in sync. .HP \fB\-\-database\fR DBI: Database identifier, see http://dbi.perl.org/ .IP defaults to a MySQL database ykksm on localhost, i.e., dbi:mysql:ykksm. For PostgreSQL on the local host you can use 'DBI:Pg:dbname=ykksm;host=127.0.0.1'. .HP \fB\-\-db\-user\fR USER: Database username to use, defaults to empty string. .HP \fB\-\-db\-passwd\fR PASSWD: Database password to use, defaults to empty string. .PP Usage example: .IP \&./ykksm\-checksum \fB\-\-database\fR dbi:mysql:ykksm \fB\-\-db\-user\fR user \fB\-\-db\-passwd\fR pencil yubikey-ksm-1.15/ykksm-import.10000644000175000017500000000204412412604401014547 0ustar jasjas.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.3. .TH YKKSM-IMPORT "1" "September 2014" "ykksm-import 1" "User Commands" .SH NAME ykksm-import \- Tool to import key data on the YKKSM-KEYPROV format. .SH SYNOPSIS .B ykksm-import [\fI\,--verbose\/\fR] [\fI\,--help\/\fR] [\fI\,--database DBI\/\fR] [\fI\,--db-user USER\/\fR] [\fI\,--db-passwd PASSWD\/\fR] [\fI\,--creator CREATOR\/\fR] .SH DESCRIPTION Tool to import key data on the YKKSM\-KEYPROV format. .HP \fB\-\-database\fR DBI: Database identifier, see http://dbi.perl.org/ .IP defaults to a MySQL database ykksm on localhost, i.e., dbi:mysql:ykksm. For PostgreSQL on the local host you can use 'DBI:Pg:dbname=ykksm;host=127.0.0.1'. .HP \fB\-\-db\-user\fR USER: Database username to use, defaults to empty string. .HP \fB\-\-db\-passwd\fR PASSWD: Database password to use, defaults to empty string. .TP \fB\-\-creator\fR CREATOR: Short string with creator info. Defaults to using the PGP signer key id, normally. you don't change this. .PP Usage example: .IP \&./ykksm\-import < keys.txt yubikey-ksm-1.15/ChangeLog0000644000175000017500000004133612412604402013601 0ustar jasjas2014-09-30 Simon Josefsson * NEWS: Version 1.15. 2014-09-30 Simon Josefsson * doc/DecryptionProtocol.txt, doc/DesignGoals.txt, doc/GenerateKSMKey.txt, doc/GenerateKeys.txt, doc/ImportKeysToKSM.txt, doc/Installation.txt, doc/KeyProvisioningFormat.txt, doc/MakeRelease.txt, doc/ServerHardening.txt, doc/SyncMonitor.txt: Editorial fixes. 2014-09-30 Simon Josefsson * doc/MakeRelease.txt: Doc fix. 2014-09-23 Simon Josefsson * doc/KeyProvisioningFormat.txt: Fix markup. 2014-09-23 Klas Lindfors * doc/KeyProvisioningFormat.txt: fix formating 2014-09-19 Simon Josefsson * selftest.sh: drop debug code 2014-09-19 Simon Josefsson * README: Update. 2014-09-19 Simon Josefsson * selftest.sh: Debug travis. 2014-09-19 Simon Josefsson * Makefile: Improve makefile. 2014-09-19 Simon Josefsson * doc/DecryptionProtocol.txt, doc/DesignGoals.txt, doc/GenerateKSMKey.txt, doc/GenerateKeys.txt, doc/ImportKeysToKSM.txt, doc/Installation.txt, doc/KeyProvisioningFormat.txt, doc/MakeRelease.txt, doc/ServerHardening.txt, doc/SyncMonitor.txt: Add wiki pages. 2014-09-19 Simon Josefsson * .gitmodules: remove more. 2014-09-19 Simon Josefsson * .gitmodules, doc: Remove doc submodule. 2014-09-12 Klas Lindfors * Makefile: set VERSION correctly in Makefile 2014-09-04 Simon Josefsson * BLURB, Makefile, NEWS: Update some URLs. 2014-08-21 Simon Josefsson * NEWS: Add NEWS entries. 2014-06-26 Klas Lindfors * .travis.yml: add php 5.6 for travis 2014-02-19 Klas Lindfors * BLURB: add BLURB 2013-11-08 Klas Lindfors * .travis.yml, selftest.sh: add sqlite support to the travis tests 2013-11-08 Klas Lindfors * ykksm-decrypt.php: change the sql syntax for active so it works on sqlite 2013-11-08 Klas Lindfors * doc: update documentation 2013-11-07 Klas Lindfors * selftest.sh: test some failures 2013-11-07 Klas Lindfors * .travis.yml: more php versions 2013-11-07 Klas Lindfors * : commit af945c4014c6e89935570b861c5cadd1d616fc9f Author: Klas Lindfors Date: Thu Nov 7 09:43:55 2013 +0100 2013-11-07 Klas Lindfors * selftest.sh: typo 2013-11-07 Klas Lindfors * selftest.sh: restructure selftest to use php on cli 2013-11-06 Klas Lindfors * selftest.sh: try to find out how the php environment looks 2013-11-06 Klas Lindfors * selftest.sh: change quotes on insert and add all columns 2013-11-06 Klas Lindfors * selftest.sh: show phpenv info 2013-11-06 Klas Lindfors * .travis.yml: add pgsql 2013-11-06 Klas Lindfors * selftest.sh: apparently not using phpenv.. 2013-11-06 Klas Lindfors * selftest.sh: try to get php right 2013-11-06 Klas Lindfors * selftest.sh: do another curl in error 2013-11-06 Klas Lindfors * .travis.yml: wait with variants 2013-11-06 Klas Lindfors * selftest.sh: spec error.log and access.log 2013-11-06 Klas Lindfors * selftest.sh: sudo when looking at logs 2013-11-06 Klas Lindfors * selftest.sh: do +e when we run tests.. 2013-11-06 Klas Lindfors * selftest.sh: try to get more information on error 2013-11-06 Klas Lindfors * selftest.sh: syntax fix 2013-11-06 Klas Lindfors * selftest.sh: else -> elif 2013-11-06 Klas Lindfors * selftest.sh: remove \r 2013-11-06 Klas Lindfors * selftest.sh: executable 2013-11-06 Klas Lindfors * .travis.yml, selftest.sh: start adding travis for yubikey-ksm 2013-11-06 Klas Lindfors * .gitmodules: change doc module to use https instead of ssh 2013-09-18 Simon Josefsson * doc: Bump doc/. 2013-09-18 Simon Josefsson * NEWS: Version 1.14. 2013-09-18 Simon Josefsson * Makefile: Fix release rule. 2013-09-18 Simon Josefsson * NEWS: Add. 2013-09-05 Simon Josefsson * NEWS: Add. 2013-07-01 Remi Mollon * ykksm-decrypt.php: oracle support 2013-04-22 Simon Josefsson * Makefile, README: Improve README. Dist it. 2013-04-17 Simon Josefsson * Makefile, NEWS: Bump version. 2013-04-17 Simon Josefsson * Makefile: Improve release target. 2013-04-17 Simon Josefsson * Makefile, NEWS: Version 1.13. 2013-04-17 Simon Josefsson * NEWS: Updated release procedure. 2013-04-17 Simon Josefsson * Makefile: Fix dist target. 2013-04-10 Dain Nilsson * Makefile: Updated release target. 2013-03-05 Dain Nilsson * : Merge pull request #2 from colinnewell/master The makefile has spaces where there should be tabs 2013-02-05 Dain Nilsson * Makefile: Fixed homepage building in make release. 2013-02-05 Dain Nilsson * NEWS: Updated NEWS for 1.12 release. 2013-02-04 Dain Nilsson * ykksm-checksum, ykksm-export, ykksm-import: Updated copyright headers. 2013-02-01 Dain Nilsson * .gitignore: Added .gitignore with build artifacts. 2013-02-04 Simon Josefsson * COPYING, Makefile, NEWS, ykksm-decrypt.php, ykksm-gen-keys, ykksm-utils.php: Update copyright information. 2013-02-04 Simon Josefsson * README: Fix ykval link. 2013-01-31 Dain Nilsson * Makefile, NEWS: Updated Makefile and NEWS post 1.11. 2013-01-31 Dain Nilsson * NEWS: Updated NEWS for 1.11. 2013-01-31 Dain Nilsson * Makefile: Added missing manprefix to Makefile. 2013-01-31 Dain Nilsson * Makefile, NEWS: Updated Makefile and NEWS post 1.10 release. 2013-01-31 Dain Nilsson * NEWS: Updated NEWS for 1.10 2013-01-31 Dain Nilsson * Makefile: Added quoting of versions for Jekyll 2013-01-30 Dain Nilsson * Makefile: Makefile fixes. 2013-01-30 Dain Nilsson * Makefile: Makefile now installs man pages. 2013-01-28 Dain Nilsson * ykksm-config.php: Added missing default db type. 2013-01-28 Dain Nilsson * ykksm-checksum, ykksm-export, ykksm-import: Fixed scripts failing when db config exists but isn't readable. 2013-01-28 Dain Nilsson * Makefile, NEWS, doc, ykksm-checksum, ykksm-config.php, ykksm-export, ykksm-import: Use yubikey-ksm instead of ykksm in paths, configuration in /etc/yubico/ksm 2013-01-23 Dain Nilsson * Makefile, NEWS: Updated versions post 1.9. 2013-01-23 Dain Nilsson * NEWS, doc: Version 1.9 2013-01-23 Dain Nilsson * NEWS, ykksm-utils.php: Renamed hex2bin to yubi_hex2bin. 2013-01-23 Dain Nilsson * Makefile, NEWS: Updated versions post 1.8 release. 2013-01-21 Dain Nilsson * NEWS, doc: Updated NEWS for 1.8 release. 2013-01-21 Dain Nilsson * Makefile, NEWS: Added ChangeLog generation to make dist. 2012-12-21 Dain Nilsson * Makefile: Fixed formatting of releases.html 2012-12-21 Dain Nilsson * Makefile, NEWS: Updated versions post 1.7 release. 2012-12-21 Dain Nilsson * NEWS: Version 1.7. 2012-12-21 Dain Nilsson * NEWS: Updated NEWS 2012-12-21 Dain Nilsson * ykksm-checksum, ykksm-config.php, ykksm-export, ykksm-import: Added support for reading db config from /etc/ykksm/ 2012-12-20 Dain Nilsson * ykksm-utils.php: Replaced the deprecated use of 'mcrypt_ecb' with 'mdecrypt_generic' 2012-12-20 Dain Nilsson * Makefile: Added man pages requirement to install. 2012-12-20 Dain Nilsson * Makefile: Added distclean to Makefile 2012-12-19 Dain Nilsson * Makefile: Makefile fixes (DESTDIR and file permissions). 2012-12-19 Dain Nilsson * Makefile: Added automated publishing of release to Makefile. 2012-12-18 Dain Nilsson * README: Corrected releases link in README. 2012-12-18 Dain Nilsson * README: Added link to GitHub Pages page to README. 2012-12-18 Dain Nilsson * Makefile, NEWS: Bumped version post release. 2012-12-18 Dain Nilsson * Makefile: Added manual entry of KEYID to make release. 2012-12-18 Dain Nilsson * NEWS: Updated NEWS for release of 1.6 2012-12-18 Dain Nilsson * doc: Updated docs. 2012-12-18 Dain Nilsson * Makefile: Updated make release to use git. 2012-12-18 Dain Nilsson * Makefile, NEWS, README, README.md: Updated NEWS. Renamed README. 2012-12-18 Dain Nilsson * Makefile: Added clean-man to clean in Makefile 2012-12-18 Dain Nilsson * README.md: Updated README with info about doc. 2012-12-18 Dain Nilsson * .gitmodules, doc: Added doc submodule. 2012-12-18 Dain Nilsson * README.md: Updated URL to yubikey-val-server-php in readme. 2012-12-18 Dain Nilsson * : commit 9f3f2373db74127c4e1fe6258aa28e9855401e94 Author: Dain Nilsson Date: Tue Dec 18 04:40:42 2012 -0800 2012-12-18 Dain Nilsson * Makefile, ykksm-checksum, ykksm-checksum.pl, ykksm-export, ykksm-export.pl, ykksm-gen-keys, ykksm-gen-keys.pl, ykksm-import, ykksm-import.pl, ykksm-upgrade.pl: Removed .pl suffix from scripts. Added man page generation to Makefile. 2012-12-18 Dain Nilsson * ykksm-checksum.pl: Replaced DIGEST::SHA1 with DIGEST::SHA. 2012-01-23 Simon Josefsson * Makefile, ykksm-checksum.pl, ykksm-decrypt.php, ykksm-export.pl, ykksm-gen-keys.pl, ykksm-import.pl, ykksm-upgrade.pl, ykksm-utils.php: Bump copyright information. 2011-01-14 Simon Josefsson * NEWS: Add. 2011-01-14 Simon Josefsson * ykksm-checksum.pl: Order by serial number first, makes more sense. 2010-11-11 Simon Josefsson * ykksm-gen-keys.pl: Fix command line handling. 2010-11-11 Simon Josefsson * ykksm-gen-keys.pl: Make the old format the default, use --pkcs to get PKSC. 2010-11-11 Simon Josefsson * NEWS, ykksm-gen-keys.pl: ykkgsm-gen-keys supports the PSKC YubiKey profile. 2010-09-21 Simon Josefsson * Makefile, NEWS: Bump versions. 2010-09-14 Simon Josefsson * NEWS: Version 1.5. 2010-09-14 Simon Josefsson * NEWS: Version 1.4. 2010-09-14 Simon Josefsson * Makefile: Fix release target. Bump revision. 2010-09-14 Simon Josefsson * NEWS, ykksm-decrypt.php: Don't use PDO rowCount. Issue #2. 2010-09-14 Simon Josefsson * NEWS: Add. 2010-09-14 Simon Josefsson * NEWS: Add. 2010-09-14 Simon Josefsson * ykksm-gen-keys.pl: Fix warning. Issue #3 reported by toddejohnson. 2010-03-16 Simon Josefsson * Makefile: Version 1.3. 2010-03-16 Simon Josefsson * NEWS: Add dates to versions. 2010-03-16 Simon Josefsson * Makefile: Dist doc/SyncMonitor.wiki. 2010-03-03 Simon Josefsson * ykksm-checksum.pl: Better ordering. 2010-03-03 Simon Josefsson * ykksm-checksum.pl: Order query. 2010-03-03 Simon Josefsson * Makefile, ykksm-checksum.pl: Add checksum tool. 2010-01-19 Simon Josefsson * Makefile: Fix. 2009-12-16 Simon Josefsson * Makefile: Prepare for release. 2009-12-15 Simon Josefsson * NEWS: Version 1.2. 2009-12-15 Simon Josefsson * Makefile: Fix release target. 2009-12-15 Simon Josefsson * Makefile: Fix. 2009-12-15 Simon Josefsson * Makefile: Fix rules. 2009-12-15 Simon Josefsson * ykksm-decrypt.php: Use require_once. 2009-12-15 Simon Josefsson * Makefile: Fix symlink rule. 2009-12-15 Simon Josefsson * Makefile: Fix install rule. 2009-12-15 Simon Josefsson * Makefile: Add symlink rule. 2009-12-15 Simon Josefsson * Makefile: Fix install rule. 2009-12-15 Simon Josefsson * Makefile: fix 2009-12-15 Simon Josefsson * Makefile: Fix install target. 2009-12-14 Simon Josefsson * Makefile: Fix perms. 2009-12-14 Simon Josefsson * Makefile: Fix. 2009-12-14 Simon Josefsson * Makefile: Add install rule. 2009-12-14 Simon Josefsson * ykksm-db.sql, ykksm-decrypt.php, ykksm-export.pl, ykksm-import.pl, ykksm-upgrade.pl: Case insensitive. 2009-12-14 Simon Josefsson * ykksm-import.pl: Improve help and fix created_by field. 2009-12-14 Simon Josefsson * ykksm-db.sql: Make portable. 2009-12-02 Simon Josefsson * ykksm-config.php: Update for PHP PDO configuration. 2009-12-02 Simon Josefsson * ykksm-decrypt.php: Use PHP PDO database interface instead of hard coding the MySQL interface. 2009-12-02 Simon Josefsson * NEWS: Add. 2009-12-02 Simon Josefsson * Makefile: Bump version. 2009-11-20 Simon Josefsson * Makefile: Less hard coding. 2009-11-20 Simon Josefsson * Makefile: Fix file description. 2009-11-20 Simon Josefsson * Makefile: Add. 2009-11-20 Simon Josefsson * : Pull in wiki to doc/. 2009-06-24 Simon Josefsson * ykksm-decrypt.php: Reorder UID/CRC check so we get only the interesting CRC errors. 2009-05-04 Simon Josefsson * .htaccess: Add. 2009-04-19 Simon Josefsson * ykksm-export.pl: Hint. 2009-04-19 Simon Josefsson * ykksm-export.pl: Chmod.x 2009-04-19 Simon Josefsson * ykksm-export.pl: Fix typo. 2009-04-19 Simon Josefsson * ykksm-export.pl: Add. 2009-04-19 Simon Josefsson * ykksm-db.sql: Be first-time install friendly. 2009-03-18 Simon Josefsson * ykksm-decrypt.php: Log return string. 2009-03-18 Simon Josefsson * ykksm-decrypt.php: Improve debugging. 2009-03-18 Simon Josefsson * ykksm-decrypt.php: Reorder high/low to match internal order. 2009-03-18 Simon Josefsson * TODO, ykksm-db.sql, ykksm-decrypt.php, ykksm-import.pl: Drop accessed field. 2009-03-11 Simon Josefsson * ykksm-decrypt.php: Accidentally reversed high/low. Rename fields slightly. 2009-02-27 Simon Josefsson * ykksm-import.pl: Fix --help. 2009-02-27 Simon Josefsson * ykksm-import.pl: Don't require progflags. 2009-02-27 Simon Josefsson * ykksm-gen-keys.pl: Support --progflags. 2009-02-25 Simon Josefsson * ykksm-gen-keys.pl: Fix --help. 2009-02-25 Simon Josefsson * ykksm-config.php, ykksm-decrypt.php: Make syslog facility configurable. 2009-02-25 Simon Josefsson * ykksm-import.pl: Cleanup temp file properly. 2009-02-24 Simon Josefsson * ykksm-import.pl: Fix --help. 2009-02-24 Simon Josefsson * TODO, ykksm-config.php, ykksm-db.sql, ykksm-decrypt.php, ykksm-gen-keys.pl, ykksm-import.pl, ykksm-utils.php: Commit initial version. 2009-02-24 Simon Josefsson * Initial directory structure. yubikey-ksm-1.15/ykksm-gen-keys0000755000175000017500000001332212412604401014624 0ustar jasjas#!/usr/bin/perl # Written by Simon Josefsson . # Copyright (c) 2009-2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use POSIX qw(strftime); use MIME::Base64; my $device = "/dev/random"; sub usage { print "Usage: ykksm-gen-keys [--verbose] [--help] [--urandom] [--progflags PROGFLAGS] [--pskc] START [END]\n"; print "\n"; print "Tool to generate keys on the YKKSM-KEYPROV format.\n"; print "\n"; print "START: Decimal start point.\n"; print "\n"; print "END: Decimal end point, if absent START is used as END.\n"; print "\n"; print " --urandom: Use /dev/urandom instead of /dev/random as entropy source.\n"; print "\n"; print " --progflags PROGFLAGS: Add a final personalization configuration string.\n"; print "\n"; print " --pskc: Output keys on the YubiKey PSKC format.\n"; print "\n"; print "Usage example:\n"; print "\n"; print " ./ykksm-gen-keys --urandom 1 10 |\n"; print " gpg -a --sign --encrypt -r 1D2F473E > keys.txt\n"; print "\n"; exit 1; } sub hex2modhex { $_ = shift; tr/0123456789abcdef/cbdefghijklnrtuv/; return $_; } sub getrand { my $cnt = shift; my $buf; open (FH, $device) or die "Cannot open $device for reading"; read (FH, $buf, $cnt) or die "Cannot read from $device"; close FH; return $buf; } sub gethexrand { my $cnt = shift; my $buf = getrand ($cnt); return lc(unpack("H*", $buf)); } sub getb64rand { my $cnt = shift; my $buf = getrand ($cnt); return encode_base64($buf, ''); } # main if ($#ARGV==-1) { usage(); } my $verbose = 0; my $pskc = 0; my $progflags; my $start = ""; my $end = ""; while (defined($ARGV[0])) { my $cmd = shift @ARGV; if (($cmd eq "-v") || ($cmd eq "--verbose")) { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq "--urandom") { $device = "/dev/urandom"; } elsif ($cmd eq "--progflags") { $progflags = "," . shift; } elsif ($cmd eq "--pskc") { $pskc = 1; } elsif ($cmd =~ m/^[0-9]+/) { if ($start eq "") { $start = $cmd; } elsif ($end eq "") { $end = $cmd; } else { die "Invalid extra argument: $cmd"; } } } die "Missing START parameter, try --help" if ($start eq ""); $end = $start if (!$end); my $now = strftime "%Y-%m-%dT%H:%M:%S", localtime; if ($pskc) { $now .= 'Z'; } my $ctr; if ($pskc) { print "\n"; print "\n"; } else { print "# ykksm 1\n"; print "# start $start end $end device $device\n" if ($verbose); print "# serialnr,identity,internaluid,aeskey,lockpw,created,accessed[,progflags]\n"; } $ctr = $start; while ($ctr <= $end) { my $hexctr = sprintf "%012x", $ctr; my $modhexctr = hex2modhex($hexctr); my $internaluid = gethexrand(6); my $aeskey = $pskc ? getb64rand(16) : gethexrand(16); my $lockpw = gethexrand(6); if ($pskc) { print " \n"; print " \n"; print " oath.UB\n"; print " $ctr\n"; print " $now\n"; print " \n"; print " \n"; print " 1\n"; print " \n"; print " \n"; print " Yubico\n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " $aeskey\n"; print " \n"; print " \n"; print " \n"; print " CN=$modhexctr, UID=$internaluid\n"; print " \n"; print " \n"; } else { print "# hexctr $hexctr modhexctr $modhexctr\n" if ($verbose); printf "$ctr,$modhexctr,$internaluid,$aeskey,$lockpw,$now,$progflags\n"; } $ctr++; } if ($pskc) { print "\n"; } else { print "# the end\n"; } exit 0; yubikey-ksm-1.15/NEWS0000644000175000017500000000464112412604401012523 0ustar jasjas* Version 1.15 (released 2014-09-30) * Fix boolean SQL portability issue for Oracle. * Add self-testing through Travis. * Update some URLs. * Version 1.14 (released 2013-09-18) * Add Oracle support via OCI. * The README is included in the tarball now. * Version 1.13 (released 2013-04-17) * Updated release procedure, project moved from Google Code to GitHub. * Version 1.12 (released 2013-02-05) * Added COPYING file. * Version 1.11 (released 2013-01-31) * Added missing manprefix to Makefile. * Version 1.10 (released 2013-01-31) * Changed location of files to /usr/share/yubikey-ksm, etc. * Changed location of configuration files to /etc/yubico/ksm/. * Fixed bug causing scripts reading the database to fail if the config file exists but is not readable by the current user. * Version 1.9 (released 2013-01-23) * Renamed hex2bin to yubi_hex2bin. Issue #1 reported by Dain Nilsson, see: https://github.com/Yubico/yubikey-ksm/issues/1 * Version 1.8 (released 2013-01-21) * Added ChangeLog to releases. * Updated documentation for building/installing. * Version 1.7 (released 2012-12-21) * Replaced usage of 'mcrypt_ecb' as it is deprecated. Issue #5 reported by Gyula Szabó, see: http://code.google.com/p/yubikey-ksm/issues/detail?id=5>. * Read database config from /etc/yubico/ksm/config-db files, as generated by dbconfig. * Version 1.6 (released 2012-12-18) * ykksm-gen-keys supports the PSKC YubiKey profile. * ykksm-checksum sorts by serial number first. * Removed .pl extension from scripts. * Added man pages. * Removed ykksm-upgrade. * Version 1.5 (released 2010-09-14) * Brown paper bag release to update NEWS and Makefile before release. * Version 1.4 (released 2010-09-14) * Don't use PDO rowCount, it is not portable. Issue #2 reported by arte42.ripe, see: http://code.google.com/p/yubikey-ksm/issues/detail?id=2>. * Fixed perl warning in ykksm-gen-keys. Issue #3 reported by toddejohnson, see: http://code.google.com/p/yubikey-ksm/issues/detail?id=3>. * Improve documentation. * Version 1.3 (released 2010-03-16) * Added ykksm-checksum tool. * Version 1.2 (released 2009-12-15) * Documentation and installation experience substantially improved. * Version 1.1 (released 2009-12-02) * Use PHP PDO instead of hard coding use of MySQL database interface. * Version 1.0 (released 2009-11-19) * Initial release.