freeradius and yubikeys

Arran Cudbard-Bell a.cudbardb at
Sun May 11 13:29:54 CEST 2014

On 11 May 2014, at 09:01, Frederic Van Espen < at> wrote:

> On Sat, May 10, 2014 at 8:01 PM, Arran Cudbard-Bell
> <a.cudbardb at> wrote:
>> Good catch. Half the original auth code got the passcode from char *passcode, and the other used VALUE_PAIR *request->password *sigh*. Ok, all uses passcode now, should work.
> Confirmed working fine now :)

Good :)

>> You know you can do the decryption locally right? You don't need to use their servers. The module didn't even have support for ykclient until they grumbled about it.
>> You can put the shared keys in LDAP as well, you just need to figure out a place to stick the replay counters.
> I do know :) I'm currently just trying to set up a small prototype,
> but admittedly, I haven't done all that much research yet on how to
> make things run locally.

You need to store 3 bits of info, where they come from is completely up to you.

It works in a similar way to using the validation server:

1. yubikey.authorize splits out the Yubikey-Public-ID, Yubikey-OTP and User-Password fields from the password string. It also sets Auth-Type yubikey.

2. You implement additional logic to get the control:Yubikey-Key value, associated with the Yubikey-Public-ID and/or User, and the control:Yubikey-Counter value associated with the Yubikey-Public-ID. If there isn't one, you set it to 0.

3. Authenticate runs with yubikey.authenticate, it converts Yubikey-OTP to binary (from modhex), and attempts to decode it using control:Yubikey-Key. It it succeeds it outputs request:Yubikey-Private-ID (which you can use for further validation), request:Yubikey-Timestamp, request:Yubikey-Random and request:Yubikey-Counter (a combination of a couple of 16 bit values from the token used to prevent replay attacks).

It then checks that request:Yubikey-Counter > control:Yubikey-Counter, and rejects the request if it's not.

Yubikey-Random is for debugging, but could be stored and compared to ensure a new random number is used for each auth. Yubikey-Timestamp is also mostly for debugging, but could be stored and compared to make sure it increased between auths.

4. In post-auth if the previous stage was successful you update your stored Yubikey-Counter
to match request:Yubikey-Counter.

You can do even neater things if you can be bothered to write the logic. For example if you keep a table with yubikey state (assigned/unassigned), pre-provision all the keys with known shared-secrets and stick them all in the table, the first time a user auths with an unassigned key, you can do auto provisioning and create the association between user and key.

Other physical token code based systems can't do this as they don't send the token ID along with the token code.

It's the reason why I wrote the module, it's the first OTP system that i've seen that doesn't completely suck. RSA tokens, and all the other little 6-8 digit pin code systems are complete shit compared to yubikey. SMS based OTP is so insecure I can't believe anyone actually uses it, the same with those stupid Java software tokens you run on smartphones.

> But I'm really going to use all this in
> production, that's certainly the way we'll go.
> Thanks a bunch for all your efforts!

Thanks for the testing and feedback!


Arran Cudbard-Bell <a.cudbardb at>
FreeRADIUS Development Team

FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 881 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <>

More information about the Freeradius-Users mailing list