wood_menu My Weblog My Gallery About me Contact me
Follow me on twitter

March 17, 2010 Archives

How to quickly setup Two-Factor SSH authentication using Yubikey

Thanks to the Geneva Application Security Forum, I'm now a proud owner of a Yubikey. This small USB token acts as an OTP (One-Time Password) generator. I'll present you a quick solution to use it within OpenSSH for Two-Factor (T-FA) authentication.

What is Two-Factor authentication ?

An authentication factor is a piece of information and process used to authenticate or verify the identity of a person or other entity requesting access under security constraints. Two-factor authentication (T-FA) or (2FA) is a system wherein two different factors are used in conjunction to authenticate. Using two factors as opposed to one factor generally delivers a higher level of authentication assurance. Two-factor authentication typically is a signing-on process where a person proves his or her identity with two of the three methods: "something you know" (e.g., password or PIN), "something you have" (e.g.,smartcard or token), or "something you are" (e.g., fingerprint or iris scan).

How does the Yubikey work ?

A Yubikey is a small USB HID device which is seen as a generic keyboard (no driver needed) with a small button. Each time the button is pressed it generates a one-time password secured using AES-128 encryption and ModHex encoding. For more details, you can have a look at this detailed article.

How to integrate a Yubikey in the SSH login process ?

There is various solutions available, one of them is to use the a PAM module, but it's still in development and users reports some crashes, so it doesn't sound a very good solution to me at this time.
The other solution (the one I'll present in this article) was to develop a script which will be invoked at each login, before giving a shell to the user, which will check the OTP.

Ok ... ok ! But how can I use it with my OpenSSH server ?

Here is the way my solution works : I've added a group called "yubikey" on the system. The SSH server will execute the authentication script for all the members of this group on each login (this is done using the sshd_config Match directive). The script will ask the user to generate an OTP using his Yubikey, check if this key is authorized for this user, parsing ~/.ssh/trusted_yubikeys then proceed to the validation of the password. If everything is fine the script gives the user his shell.
Here are all the steps in detail :

Create the group :

$ groupadd yubikey

Add your user inside the group :

$ adduser mon_user yubikey

Specify the trusted keys for this user :

$ cd /home/mon_user/.ssh
$ echo "yubikeyid" >> trusted_yubikeys

Create the script in /usr/local/bin/yubikey.sh :

#!/bin/bash
#
# (c) 2010 Alexandre De Dommelin
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
#

YUBICO_API_ID="XXXX"
TRUSTED_KEYS_FILE="$HOME/.ssh/trusted_yubikeys"

STD="\\033[0;39m"
OK="\\033[1;32m[i]$STD"
ERR="\\033[1;31m[e]$STD"

##################################################
## Disconnect clients trying to exit the script ##
##################################################

trap disconnect INT
disconnect() {
  sleep 1
  kill -9 $PPID
  exit 1
}


echo ""
echo "** One-Time Password Validation Step **"
echo ""

echo -n "Please provide Yubi OTP then enter Ctrl-d: "
OTP=`tr -c -d a-z < /dev/tty`
KEY_ID=${OTP:0:12}


####################################
## Get user-trusted yubikeys list ##
####################################

if [ ! -f $TRUSTED_KEYS_FILE ]
then
  echo -e "$ERR Unable to find trusted keys list"
  disconnect
else
  TRUSTED_KEYS=`cat $TRUSTED_KEYS_FILE`
fi



#######################################
## Iterate through trusted keys list ##
#######################################

for trusted in ${TRUSTED_KEYS[@]}
do
  if [ $KEY_ID = $trusted ]
  then
    echo -e "$OK Found key in $TRUSTED_KEYS_FILE - validating OTP now ..."

    if wget "https://api.yubico.com/wsapi/verify?id=$YUBICO_API_ID&otp=$OTP" -O - 2> /dev/null | grep "status=OK" > /dev/null
    then
      echo -e "$OK OTP validated"

      exec `grep "^$(whoami)" /etc/passwd | cut -d ":" -f 7`
    else
      echo -e "$ERR Unable to validate generated OTP" > /dev/stderr
      sleep 1
      disconnect
    fi
  fi
done

echo -e "$ERR Key not trusted" > /dev/stderr
disconnect

Give it the right permissions :

$ chmod 755 /usr/local/bin/yubikey.sh

Configure /etc/ssh/sshd_config with this parameters :

Match group yubikey
        ForceCommand /usr/local/bin/yubikey.sh

Then restart SSH server :

$ /etc/init.d/ssh restart

Important notes

  • Keep an active SSH session during your tests :-)
  • You have to put your API ID in YUBICO_API_ID inside the script. API ID can be obtained at api.yubico.com
  • Make sure that ~/.ssh/trusted_keys is readable by the matching user
  • Of course, you can use your own validation server, just adapt the script accordingly
  • I'm not responsible of what you do, this script works for me, but it comes with no warranty, if your dog die tomorrow or anything else like that don't blame me
  • Updated versions will be commited to my Github repository

Posted by Alexandre De Dommelin on Wed Mar 17 20:00:00 UTC 2010 | Permanent Link | Categories: Articles