You are hereOther / Using Yubico's YubiKey with freeRadius, PAM and a local validation server

Using Yubico's YubiKey with freeRadius, PAM and a local validation server


By maho - Posted on 27 January 2009

First of all a few words on this project, the documentation on the modules where there is anything that could even qualify as documentation is quite bad, there are confusing project pages were some projects have tar balls and some where you need to use svn to download, some repositories were offline, to top that the tomcat that is delivered with at least CentOs5.2 is incompatible with mysql.
Don't get me wrong I think that Yubico got something really cool and useful here but, for an organization that do not wish to use the Yubico validation servers there is a lot of work to be done. Hopefully this document will be able to save some time for the next sysadm who descided to give Yubico a shot since RSA don't reply quickly enough to emails, which when all comes to it Yubico really don't either(in my world more than 4 hours is too slow), they don't even answer their phones at their Stockholm office :) anyway I finally got it up and running and here is how I did it.

Getting everything we need:
Download the following stuff
Freeradius - http://freeradius.org/download.html
libyubikey-client - code.google.com/p/yubico-c-client/
yubico-pam - code.google.com/p/yubico-pam/
yubikey-server-j (wsapi) - code.google.com/p/yubikey-server-j/
server-j database setup script - forum.yubico.com/yubico-val-server/db_schema.sql
tomcat5 - tomcat.apache.org/download-55.cgi
java SDK - java.sun.com/javase/downloads/

You will also need a mysql5 server and curl-devel packages installed, but you can get those from your package manager.
And last but not least, get the AES keys for your yubikey(s), an email to support@yubico.com should be enough for that, it took about a half working day for the response which gave access to the yubikey management site where you can get AES keys for all your yubikeys and the ones you buy in the future.

Java
Not much to say here, install the java SDK and remember where you put it.

Tomcat5
The tomcat installation is pretty straight forward:

untar
mv apache-tomcat-5.5.27 /opt/tomcat-5.5.27
ln -s /opt/tomcat-5.5.27 /opt/tomcat

Copy the downloaded wsapi.war (server-j) to /opt/tomcat/webapps
Append the following to your rc.local
echo 'export CATALINA_HOME=/opt/tomcat' >> /etc/rc.local
echo 'export PATH=$PATH:$CATALINA_HOME/bin' >> /etc/rc.local
echo 'export JAVA_HOME=/usr/java/latest/' >> /etc/rc.local
echo '/opt/tomcat/bin/catalina.sh start' >> /etc/rc.local

Either run rc.local or restart computer.

Mysql, database setup
This is also pretty straight forward, one thing to remember, dont change 'readwrite' or 'password' if you do you will have to update /opt/tomcat5/webapps/wsapi/WEB-INF/web.xml

mysql -uroot -proot_password
create database yubico;
grant all privileges on yubico.* to 'readwrite'@'localhost' identified by 'password';
flush privileges;
quit;

Run the database setup script

mysql -uroot -proot_password yubico < db_schema.sql

This is where the original documentation get out of sync, there is only one item in the clients database so the following query will not do any harm, but to be safe, the script might have changed since I downloaded it you should probably have a look before executing it.

mysql -uroot -proot_password yubico
update clients set created='2009-01-26 14:46:21', email='root@mydomain.tld';

If you have received your AES keys here is how to add them it is important to set a valid date because the server-j(wsapi) can not handle the default value of those columns.. I guess that I should mention that it is the base64 keys you should put in the database.

insert into yubikeys (client_id, tokenId, secret, created, accessed) values(1, [yubikey id],[aes secret key],'2009-01-26 23:04:00','2009-01-26 23:04:00');

Management web portal

So these are my notes during this incredible frustrating setup, I will clean it but not right now, have fun trying to decrypt :)

yms, phpbaselib & php lib something..

before we begin make sure that the follwing is set inte php.ini
session.use_cookies = 1
session.auto_start = 1
session.cookie_lifetime = 0

The database setup script that is recomended by the documentation needs to be altered to fit the setup we got, they basically want to create the client, yubikeys and perms tables again, we dont..

SET character_set_client = utf8;
CREATE TABLE `admin` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `keyid` int(11) NOT NULL default '0',
  `note` varchar(45) default NULL,
  `pin` varchar(120) default NULL,
  `last_access` datetime default NULL,
  `ip` varchar(45) default NULL,
  `creation` datetime default NULL,
  `client` int(11) NOT NULL default '0',
  `timeout` int(10) unsigned NOT NULL default '3600',
  PRIMARY KEY  (`id`),
  KEY `FK_admin_2` (`keyid`),
  KEY `FK_admin_1` (`client`),
  CONSTRAINT `FK_admin_1` FOREIGN KEY (`client`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `FK_admin_2` FOREIGN KEY (`keyid`) REFERENCES `yubikeys` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1;

CREATE TABLE `buyers` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `email` varchar(100) default NULL,
  `created` datetime default NULL,
  `addr` varchar(200) default NULL,
  `qty` int(10) unsigned default NULL,
  `client_id` int(11) NOT NULL default '0',
  `name` varchar(45) default NULL,
  PRIMARY KEY  (`id`),
  KEY `FK_client_id_1` USING BTREE (`client_id`),
  CONSTRAINT `FK_client_info_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2201 DEFAULT CHARSET=latin1;

CREATE TABLE `history` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `usrid` int(10) unsigned NOT NULL default '0',
  `note` varchar(45) NOT NULL default '',
  `ip` varchar(45) NOT NULL default '',
  `creation` datetime NOT NULL default '0000-00-00 00:00:00',
  `keyid` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`),
  KEY `FK_hist_1` (`usrid`)
) ENGINE=InnoDB AUTO_INCREMENT=347 DEFAULT CHARSET=latin1;

alter table clients add `notes` varchar(100) default NULL;
alter table clients add `chk_sig` tinyint(1) NOT NULL default '0';
alter table clients add `chk_owner` tinyint(1) NOT NULL default '0';
alter table clients add `chk_time` tinyint(1) NOT NULL default '1';
alter table yubikeys add `notes` varchar(100) default NULL;
alter table yubikeys add `serial` varchar(45) default NULL;

copy config.php.sample to config.php
open config.php with an editor and change
$opt, a key from you yubikey
$pin, your pin to use when accessing YMS
$aesParams['__ADM_KEY_SECRET__'], your yubikeys AES secret
$aesParams['__ENC_KEY_SECRET__'], secret to use when encrypting data in the database, keep this one safe for future use
$baseParams['__DB_HOST__'], database host
$baseParams['__DB_USER__'], database user
$baseParams['__DB_PW__'], database password
$baseParams['__DB_NAME__', database name
$baseParams['__ROOT_EMAIL__'], your email address or whoever is responsible for this
$baseParams['__ORDER_URL__'], url to user yubikey request form perhaps?
$baseParams['__DOMAIN__'], your domain
$baseParams['__DOC_ROOT__'], filesystem path to apache root
$valParams['__VAL_URL__'], validation server URL if you have followed my instructions it should be http://localhost:8080/wsapi/verify?id= make sure that this one does not point to verify.php which is the default value.
$headParams['__SHORTCUT_ICON_URL__'], URL to favicon, should be located in yms/images
$letterParams['__KMS_URL__'], URL to yms, why the keep calling it kms is a mystery :)

When finished save and close config.php
before you can go on and run the installer you need to install yubikey-val-server-php in to yourwebroot/wsapi since there are undocumented dependencies to a file in that package..

The script will try to create the first user which already exists so we need to modify the script, open install.php and remove the entire variables starting with
$stmt = 'INSERT INTO clients VALUES (1,1,1,' .
and
$stmt = 'INSERT INTO yubikeys VALUES (1,1,1,' .
or just remove quert($stmt); beneath those variables.

run install.php, php install.php
the install script is very likely to fail a few times, that is no problem just correct the problem and run the script again..

After a successful run of install.php open config.php and remove everything between the remove this section comments.

copy yms to your web server root and rename it to kms

touch /tmp/kms.log;chown apache.apache /tmp/kms.log

In yubiphpbase/key_lib.php there is a function that sets $id to default if no $id is provided, I don't know what this is and it will not work unless there is a id 28 in the clients table, I just set to to 1 to make it work, I have no idea what the impact on security or other functionality will be..
function verifyYubikeyOtp($otp, $id=28) > function verifyYubikeyOtp($otp, $id=1)
If I can find some time I might patch this but for now, good enough..

YMS/KMS installation complete, pick a browser and navigate to http://[validationserver]/kms/index.php authenticate using you yubikey and pin(set in config.php at install)

libyubikey-client

Now things gets really interesting, the current version(1.10) of libyubikey-client is not compatible with the current version of server-j(1.0), first of all it is hardcoded to talk to api.yubico.com and sencond it parses the response from server-j in a way that simply does not work.

Untar libyubikey-client and make a backup copy of libykclient.c
apply the folloving patch to libykclient.c, I'm pretty sure that this patch is not the way a developer would have taken to solve the problems but it works and that is good enough for me.
228c228
<     url_template = "http://api.yubico.com/wsapi/verify?id=%d&otp=%s";
---
>     url_template = "http://127.0.0.1:8080/wsapi/verify?id=%d&otp=%s";
265d264
<
266a266,267
>   strtok(status, "\n");

Save and close libykclient.c.
To build and install run
./configure --prefix=/opt/libyubikey-client-1.5
make
make install

yubico-pam

The current documentation for the pam module seems to be a bit older than the module it self and does not mention som of the thing that we will do next.

Untar yubico-pam, build, install it and link it to /lib(64)/security
./configure --prefix=/opt/pam_yubico-1.10 --with-libyubikey-client-prefix=/opt/libyubikey-client-1.5/
make
make install

ln -s /opt/pam_yubico-1.10/lib/security/pam_yubico.so /lib64/security/pam_yubico.so

In theory you just add "auth        sufficient    pam_yubico.so" to the top of the pam.d object that you wish to authenticate through the yubikey validator, this however did not work on my centos 5.1 machine and I have currently no solution for that. authentication works just fine but after the yubico pam modules give success something segfaults and I have not been able to findout what or why, I will ofcourse update this as soon as I do.

But for now nevermind that the pam integration does not work, it will work with radius since radius does not spawn off a shell for the user and that is where it fails, so lets go on and create the /etc/pam.d/radiusd config here is a copy of mine

#%PAM-1.0
auth        required    pam_yubico.so id=1 authfile=/opt/pam_yubico-1.10/etc/userkeys debug
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth       include      system-auth
account    required     pam_nologin.so
account    include      system-auth
password   include      system-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    include      system-auth
session    required     pam_loginuid.so
session    optional     pam_console.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open
session    optional     pam_keyinit.so force revoke

If you wish to have the user enter his password before the yubikey just add "auth        required    pam_unix.so nullok try_first_pass" beneath pam_yubikey.so

I guess you are thinking what the hell, I don't have any /opt/pam_yubico-1.10/etc/userkeys, that's the next step.
The computer needs to know which users that are allowed to use which yubikeys, you can either set it up on a user level with a ~/.yubico/authorized_yubikeys or you could do as I did and use a server wide file /opt/pam_yubico-1.10/etc/userkeys the contents of those files should be "username:yubikey ID" if you chose the server wide path you put all your users and their keys in one file and if not you put the user name and keys of the people allowed to logon as the user who owns the home directory where the file is located, kinda like kerberos .k5login files.

Freeradius

Just untar, build and install freeradius

./configure --prefix=/opt/freeradius-x.x.x
make
make install

In /opt/freedarius-x.x.x/etc/raddb/radiusd.conf change both user and group to root
In /opt/freeradius-x.x.x/etc/raddb/sites-available/default uncomment "pam" (without the quotes)
And in /opt/freeradius-x.x.x/etc/raddb/users set "DEFAULT Auth-Type" to "pam" (without the quotes)
And as a final note, dont forget to have the authenticating users in /etc/passwd.
Start radius and we are good to go!

At last to test everything run
"radtest maho gzdrginywuctilejvngibjibltvgetfhlncikmfibiek localhost 1 testing123"

it should return something similar to this
Sending Access-Request of id 31 to 127.0.0.1 port 1812
        User-Name = "maho"
        User-Password = "
gzdrginywuctilejvngibjibltvgetfhlncikmfibiek"
        NAS-IP-Address = 127.0.0.1
        NAS-Port = 1
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=31, length=20

 

Post new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.