Recently, i played around with (time based) RFC conform one time password tokens. You know, these small fobs that display a different 6 digit PIN every minute. Recently, these have been RFC'ed, and some vendors produce them very cheap.

To use them, RADIUS servers are a good start. With a running RADIUS server, you can use them with openssh, openvpn and a bunch of other network services.

After looking into the documentations of pre-existing RADIUS servers, i developed a rather nasty headache. So, in true PerlMonks style, i boldly stepped forward, asked the world "How hard can it be???" and spent the next few hours developing an even bigger headache. But finally, a minimal, working RADIUS server/client pair
came into being. Here is how i did it:

Next, we are going to use RADIUS::Packet to write our server. This module has a rather unfortunate design decision (i would call it a bug): If it encounters a chunk of unknown type (one that is not in the dictionary), it dies. Since you never find out which type is missing in your dictionary, this is a bit ugly to debug. The following patch will remedy that problem:

Here we go. We need a server that run UDP on port 1812 on localhost. We also want to change the name displayed in "ps" (in linux/unix). The server itself will be handled by a package named Rader, and we'll hardcode it to a single authentification package "OATHusers", which in turn hold the hardcoded usernames/hashvalues pairs for all tokens. Lets start with the startscript:

We could, of course, do all the low-level UDP handling ourself, like we all learned from the Perl Cookbook. But we wont. Let's just use the very good Net::Server::Single package as base class (exchange it for Net::Server::PreFork if you got hundreds of requests per second). As for the rest: We take the packet data, turn it into a RADIUS::Packet, get username/password, check against OATHusers and then either return a 'Access-Accept' or 'Access-Reject' RADIUS::Packet.

Finally, we need some way to validate keys. All users also know a fixed, numeric PIN code (which is actually alphanumeric in this implementation) with varying length they have to prepend to the PIN of time based token. For reference, we also add the serial number (key_id) of each token to our list.

The correct time based token PIN is calculated from its seed plus the current time. Since the token clock and the computer clock might differ a bit (the clock drift usually gets worse with token age) and also the user might take some time to click "connect", we search a limited timespace for a matching key. This opens - in theory - a larger attack window, but this can't really be avoided (but mitigated through some methods like only accepting newer keys than the last valid one, tracking the time difference between token and computer, etc. This is not implemented here). Also, an attacker would need the users fixed PIN in addition to the generated PIN, even if (s)he has access to the token ("something you know and something you have").

I can't give you the specifics on how to set up openssh or similar to use RADIUS. This depends too much on your operating system and distribution. But it should be easy enough.

I tested this with real keys (and without the probable typos i introduced by converting the code to a PM article) with some "OTP c200" keys i bought online from Gooze.

Note: I'm in no way affiliated with that company, i just bought a bunch of keys from them and found pricing and delivery times rather acceptable. From my experience, this is rather unusual for cryptographic stuff bought online in europe...

"You have reached the Monastery. All our helpdesk monks are busy at the moment. Please press "1" to instantly donate 10 currency units for a good cause or press "2" to hang up. Or you can dial "12" to get connected directly to second level support."

PAM_RADIUS for Linux/UNIX and pGINA for Windows come to mind. Never used pGINA. We did play with the PAM_RADIUS module a few years back, but we ended up going with the official PAM_RSA module for support reasons (large corporation here, so for better or worse, those things matter).

When putting a smiley right before a closing parenthesis, do you:

Use two parentheses: (Like this: :) )
Use one parenthesis: (Like this: :)
Reverse direction of the smiley: (Like this: (: )
Use angle/square brackets instead of parentheses
Use C-style commenting to set the smiley off from the closing parenthesis
Make the smiley a dunce: (:>
I disapprove of emoticons
Other