OTP is a protocol for generating single-use passwords used for safer authentication than you would get by using a password directly. The system is challenge/response authentication similar to SSH keys, but with the keys and hashes reduced to something you can actually type in in a reasonable amount of time. While not absolutely secure (nothing is), one-time passwords greatly reduces the window of vulnerability compared to using static passwords directly.

For example, suppose you want to log in to one of your machines from a remote, untrusted teminal (e.g. from an internet café). You obviously don't want to load your SSH key on the untrusted terminal, and a keylogger would capture your password if you used it directly. By using a one-time password, the risk is reduced. A keylogger on the untrusted terminal could capture your one-time password and use it to log in either instead of you or as part of a man-in-the-middle attack. However, after that login is terminated, the keylogger can make no further breaches, as they could if they had captured your password itself. This “small window” risk is the same problem faced by sites that send you plain text emails with one-time URLs for registration confirmation, password reminders, etc. (who can't be bothered to use PGP, sigh).

For more information on one-time passwords, take a look at the following standards:

  • RFC 2289 (A One-Time Password System, obsoletes RFC 1928)
  • RFC 1938 (A One-Time Password System, obsoletes RFC 1760)
  • RFC 1760 (The S/KEY One-Time Password System)

Sound good? Alright, how do we setup SSH to accept one-time passwords on Gentoo?

OpenSSH's SSH daemon supports OTP authentication by default. If you have disabled the support, you'll need to restore it by adding

ChallengeResponseAuthentication yes

to /etc/ssh/sshd_config and running

# /etc/init.d/sshd reload

From the sshd_config(5) man page, having challenge/response authentication enabled allows all all authentications styles from login.conf(5). /etc/login.conf doesn't exist on my Gentoo or Debian systems, which is, I think, because they use PAM to handle all the authentication. Tracing through /etc/pam.d/, /etc/pam.d/sshd builds the following auth chain on my Gentoo system:

auth  required  pam_tally2.so onerr=succeed
auth  required  pam_shells.so
auth  required  pam_nologin.so
auth  required  pam_env.so
auth  required  pam_unix.so try_first_pass likeauth nullok
auth  optional  pam_permit.so

We need to add an OTP PAM module. There are several, none of which seem to be actively developed:

  • S/Key (last activity in 2007)
  • OPIE (only maintained by Debian?)

The S/Key module does, however, have an ebuild in Gentoo's portage tree (significantly patched from upstream), so we'll use that.

My initial idea was to add skey to USE and run

# emerge -av --deep --update --newuse @world 

but that enabled built-in S/Key handling in app-admin/sudo and similar packages. We don't want applications to use S/Key directly, we want them to use PAM, and PAM should use S/Key. So instead, just emerge the S/Key PAM module:

# emerge -av sys-auth/pam_skey

which will pull in the sys-auth/skey package containing binary tools and the libskey.so library.

Configure PAM to use the skey module for all system authentication by adding a line like:

auth [success=done ignore=ignore auth_err=die default=bad] pam_skey.so

before the pam_unix.so line in /etc/pam.d/system-auth. This allows users to use their one-time password (if configured) and falls back to their system password if OTPs are not setup or the entered OTP is invalid. See /usr/share/doc/pam_skey-*/INSTALL.bz2 for details on this specific case and the PAM System Administrators' Guide for details on the syntax. Gentoo's pam_skey has been patched up a good deal (see /usr/share/doc/pam_skey-*/README.bz2), so on other systems, the procedure may be different (e.g. OpenBSD has the S/Key module installed by default).

Setup a one-time password chain for a particular user by running

$ skeyinit
Password: 
[Adding wking]
Reminder - Only use this method if you are directly connected
or have an encrypted channel.  If you are using telnet
or rlogin, exit with no password and use skeyinit -s.

Enter secret password: 
Again secret password: 

ID wking skey is otp-md5 99 tyr24366
Next login password: RIM CHUG MUSH LOFT SAFE CHAR

there are a number of options you can pass to skeyinit to customize the OTP (hash, effected user, etc.).

That configures your server to accept RFC 2289 passwords. On the client side, you'll need a generator to calculate the appropriate response to server challenges. There are a number of choices:

  • S/Key (Gentoo: sys-auth/skey) Gentoo's version of the OpenBSD package contains the command-line skey supporting RFC 2289 and RFC 1760.
  • otpCalc (Gentoo: sys-auth/otpcalc) RFC 2289 and RFC 1760 compliant calculator using GTK+.
  • OTPGen RFC 2289 compliant calculator using the Java 2 Micro Edition (most mobil phones).
  • jotp RFC 2289? and RFC 1760 compliant calculator using Java with MD4 and MD5 support.

If you don't have a secure client (e.g. cell phone) that will be accessible from the untrusted terminal, you can also print a list of future OTPs and cary the paper on your person.

$ otp-md5 -xn 5 99 tyr24366
Reminder - Do not use this program while logged in via telnet or rlogin.
Enter secret password: 
 95: WENT FORM GAUL DATA LYLE SIR       FA10 A627 37FB 5078
 96: DINE RODE SANK LYON SUCH MEAT      735A 275B 5AAE 4972
 97: THEE TOUR GOES HULK WORM TROY      EA1D D238 4E4F DFE0
 98: ELM RUB CULL ANY LIND HOBO         1167 21B5 014A FD32
 99: RIM CHUG MUSH LOFT SAFE CHAR       37CC D302 D8BD 56CA

The printed paper is obviously less secure, because it reduces the authentication requirement from something-you-know (secret key) to something-you-have (paper). If that bothers you, take a look at Markus Kuhn's OTPW package, which uses a different algorithm to genrate OTPs that all begin with a secret (memorized) prefix. Kuhn's approach requires a hacker to copy your paper list and log your keystrokes to extract your prefix.

Eventually, your stock of OTPs will run low, and you'll need to use skeyinit again to provide a fresh stash.

Besides RFC 2289, there are alternative one-time password generation possibilities. RFC 4226 (HOTP: An HMAC-Based One-Time Password Algorithm) defines a particular (inferior?) one-time password generation alogrithm. This Debian post describes a FreeAuth implementation that uses time-based keys similar to many commercial systems. The SOTP module doesn't specify it's algorithm, but it has the option of using secret prefixes along the lines of OTPW.