YubikeyHelp
This page aims at clarifying a few points about the Yubikey and creating your own validation system, to complement the existing documentation.
/!\ Beware you need to change the key data in you Yubykey to be able to manage your own accounts, and doing so will prevent you from using Yubiko special services (most being available for demonstration purpose, and most being replacable, like having your own OpenID server; but you can still have a second key if you want to access Yubiko's services).
<<TableOfContents(3)>>
Understanding the Key Usage
Before we go, you must understand this key is not designed to allow subscribing to different providers (like with distributing SSH public keys), but to contain full or partial credentials for one account on a particular provider. If you need to access say your own machines and your staff corporate machines via SSH and PAM+yubikey for example, then you must have two keys. As this is symetrical cryptography, both ends needs to access the secret and i guess you would not share your key between your personnal accounts and staff accounts. In this model, an account provider programs keys and distribute them among its users, which is perfectly appropriate for personnal or corporate purpose but not for a service provider. Nevertheless, your provider can act as an authentication service provider too, using OpenId for example, and then allowing sharing your account with several other service providers.
Understanding the Key Internals
The yubikey hold several interresting data inside. A few of them can be modified by the user :
- public name (0 to 16 characters): the publicly advertised name of the key
- private name (6 characters): the secret name of the key
- management password: a secret used to allow changing the key data
- AES key (32 characters hexa): the secret key used to create the OTP
The public name can be whatever you want; you can, for example, set it to an empty string if you don't want to disclose to which it belongs (in case the key is lost), or use the name of your company, or even the name of the user, ... This field is often called the fixed part.
The private name can be whatever you want. It is not an important part of the security system, but can be used to identify the key uniquely. It can hold the real username for exemple (or a number, as the field is quite limited in length). It can also be used to shared the same AES key among user and still be able to distinguish the keys (to be able to revoke key rights if the key was lost, for example). This field is often called the uid part.
The management password is necessary to be able to change the data of the key. Beware not to loose it or you'll never be able to modify it (even if it seems to be possible to use the AES key instead, but i guess you would have lost it either). This field is often called the acc_code part.
The AES key is a secret number used to encrypt data and do the real security stuff. This field is often called the key part.
Also note the counter is never reseted, nor can it be modified, and is not designed to wrap. This is a security design decision, which implies the key would just stop working when it has been used too much. Happily, a better security device would exists long before it dies under most common usage. You can plug the device 65535 times before death, which correspond approximatively to 25 insertions/removals every day for 7 years, or 5 insertions/removals every day for 35 years.
The key does not disclose anything inside. When you push the button (or use the double-capslock sequence in the key with no button, an OTP is generated, but there is no way to get any other output. If you have the AES key, then you're able to decrypt the OTP and validate the identity of the user. In the OTP is also included a few other interresting information:
- private name (explained above)
- counter: number of times the key was connected (pluggued to an USB port)
- use: number of OTP generated in a session (a session begin when the key is pluggued, and finish when it is removed)
But, as said, the counter and use cannot be obtained without generating an OTP and decrypting it; nevertheless, it can be used by the validation server.
Creating your own Key
Installing the Personnalization Tool
First, you need to install a library providing all the necessary functions for the personnalization tools (not packaged yet). Get the latest tarball from this page (currently 1.4) and uncompress it.
Install the needed build dependencies:
apt-get install build-essential
In the source directory:
./configure make make install
(This will install things in /usr/local, but you can pass parameters to the configure script to install it elsewhere)
Then, we can install the tools (not packaged yet). Get the latest tarball from this page (currently 0.92) and uncompress it.
Install the needed build dependencies:
apt-get install libusb-dev
In the source directory:
./configure make make install
(This will install things in /usr/local, but you can pass parameters to the configure script to install it elsewhere)
Updating the Key Data
You must provide the uid parameter in hexadecimal format. Remember it is a 6 characters long string (not less, not more). You can convert a string to hexadecimal like this:
# echo -n "user01" | hexdump -v -e '1/1 "%02x"' 757365723031
You must provide the public name (fixed) parameter in either the hexadecimal or modhex format. The modhex format is a special encoding used to ensure characters sent by the key are always correctly interpreted whatever keyboard layout you use. You can convert a string to hexadecimal like this:
# echo -n "Foo Corp" | hexdump -v -e '1/1 "%02x"' 466f6f20436f7270
You can convert a string to modhex like this:
# modhex "Foo Corp" fhhvhvdcfehvidic
You can then generate a new key with the uid and fixed parameters, either with the public name in hexadecimal format:
# ykpersonalize -ouid=757365723031 -ohexfixed=466f6f20436f7270 Passphrase to create AES key: Firmware version 1.3.5 Touch level 8864 Program sequence 19 fixed:fhhvhvdcfehvidic uid:igiehgideceb key:vujkuvbhchbfihjllrlhjvennfhvfdgt acc_code:cccccccccccc ticket_flags:APPEND_CR config_flags:
or with the modhex format:
ykpersonalize -ouid=757365723031 -ofixed=fhhvhvdcfehvidic Passphrase to create AES key: Firmware version 1.3.5 Touch level 8864 Program sequence 20 fixed:fhhvhvdcfehvidic uid:igiehgideceb key:jlevvbgtbueebltnielgfcvfdldthbbd acc_code:cccccccccccc ticket_flags:APPEND_CR config_flags:
Your AES key is given in the key field. I suggest you use an empty password until you're ready for production (it is the acc_code field).
/!\ If you experience the following error:
USB error: could not claim interface 0: Device or resource busy
you can work around this problem with this tip. If it still doesn't work, you can try unbinding the device using the tip at the end of this thread.
You could also provide the AES key with the -a option, and various other options, but it is out of scope of this document. Check the ykpersonalize documentation for more information.
Each time the key data is updated, the Program sequence is increased.
The Validation System
The system is split into 3 pieces:
- the Key Storage Module (KSM), in charge of storing keys data and validating OTPs
- the Validation Server, in charge of authorizing access after validating the OTP via a list of KSM and checking security policies
- the Management Server, allowing administrators to add/revoke keys and change policies, users to revoke their keys if lost, and gather accounting information
This then defines an AAA system.
In this document we will explain how to setup the two first pieces, as the third one is not necessary to get a working and secure system.
The KSM
In this tutorial, we'll use the PHP KSM server provided by Yubiko. The installation phase is properly described in this page, so this document won't duplicate information. The main problem after the systeme is ready, is to properly feed the database, which is the problem addressed here.
This KSM suggest using a file especially formated for adding many keys at once with the provided ykksm-export.pl script. For security purpose this file should be PGP signed by the user and sent to the administrator, with the content encrypted against the administrator's PGP key. This also avoid storing clear text sensitive files. This method may or may not be used, as you can simply add keys directly to the database using, for example, phpmyadmin.
Here is the meaning of each database field:
- serialNr: this is the serial number of the key, which can be found with the barcode on the pocket of your card; it is an optional and purely informational field
- publicName: the public name of the key in modhex format (would be fhhvhvdcfehvidic in the previous examples)
- created: the ISO8601 formated key creation date; it is a purely informational field
- internalName: the uid in hex format (would be 757365723031 in the previous examples)
- aesKey: the AES key in hex format
- lockCode: the key password; it is an optional and purely informational field (but better not loosing it)
- creator: the sending user PGP key number (if you used the ykksm-export.pl script); it is an optional and purely informational field
- active: boolean used to activate or suspend the key
- hardware: boolean for an unknown usage (perhaps some planned feature); it is an optional field
In the provided SQL script, the creator field is limited to 8 characters, but recent GNUPG utility return a 40 character key number, so you may want to extend it.
Considering the publicName field is modhex encoded, and the ykpersonalize tool returns modhex data, i choose to modify the program to accept modhex data for internalName and aesKey fields too. If you want to do so, use the following patch:
--- ykksm-decrypt.php.orig 2009-06-06 22:38:51.000000000 +0200 +++ ykksm-decrypt.php 2009-06-06 22:43:59.000000000 +0200 @@ -73,8 +73,8 @@ } $row = mysql_fetch_assoc($result); -$aesKey = $row['aesKey']; -$internalName = $row['internalName']; +$aesKey = modhex2hex($row['aesKey']); +$internalName = modhex2hex($row['internalName']); $ciphertext = modhex2hex($modhex_ciphertext); $plaintext = aes128ecb_decrypt($aesKey, $ciphertext);
With this patch applied, the aesKey would be jlevvbgtbueebltnielgfcvfdldthbbd in the latest example.
Your KSM is now complete. You can use curl to test your installation, as described in the testing procedure at the end of the official installation recipe.
The Validation Server
In this tutorial, we'll use the PHP validation server provided by Yubiko. The installation phase is properly described in this page, so this document won't duplicate information. The main problem after the systeme is ready, is to properly feed the database, which is the problem addressed here.
It is important to note this server is one possible implementation of a validation server. This one follows the Yubiko's specification, but it is not the only possible system. In this one a key must be associated with some kind of account defined in the SQL database in the clients table.
Here is the meaning of each database field of this table:
- id: numerical user identifier
- active: boolean used to activate or suspend the account
- created: the ISO8601 formated account creation date; it is a purely informational field
- secret: special secret (see explanation below)
- email: the email of the user; it is an optional and purely informational field
- notes: administrator's notes about the user; it is an optional and purely informational field
The secret is used to create a HMAC signature for each message when it is not possible to contact the validation server securely, to ensure the request comes from the good user and the answer comes from the good server, to avoid a man-in-the-middle attacks. Then, if you cannot use HTTPS, you should make sure to use this shared secret between the user and validation server to improve things a bit. Beware the current implementation is broken, because if you use an insecure protocol, it doesn't enforce using a message signature. If you use a secure protocol, like HTTPS (and got the CA certificate properly to be able to trust the server replies), then your security level is much higher and you don't need to care about it (you can then leave the secret field empty).
The id field is necessary in this implementation, because it allow matching the OTP received with a user account. Without it it would not be possible to find the correct secret for the HMAC signature (because the secret is different for each user). It is also useful to gather user's statistics. If you use a secure protocol and don't care about these user information, then you might det rid of it if you wrote another validation server implementation.
Each time a valid OTP is found, a record of the latest key information is kept (or made the first time) in the yubikeys table. Here is the meaning of each database field of this table:
- id: the numerical user identifier (corresponding to the account in the clients table)
- active: boolean indicating if the key is active or suspended in the KSM ( /!\ this field is always TRUE due to a broken implementation)
- created: time when the OTP was validated
- publicName: public name of the key
- internalName: uid of the key ( /!\ this field is always empty due to a broken implementation)
- counter: number of times the key was connected (pluggued to an USB port)
- low: part of an internal key timestamp
- high:part of an internal key timestamp
- sessionUse: number of OTP generated in a session (a session begin when the key is pluggued, and finish when it is removed)
The counter, sessionUse, low, and high fields are used to prevent replay and phishing attacks. These are the security policies of the validation server. One could improve the software to add more checks.