Contents ======== 1. Introduction a. Security concerns b. Contact c. History 2. Installation 3. Passcode generation algorithm 4. Demo (Screenshot!) 4. About PAM (short talk) More details about how PAM works 5. Licensing 1. Introduction =============== A one-time password (OTP) is a password that is only valid for a single login session or transaction (usually along a normal static password). Using them reduces risks associated with login into your system from unsecure (keylogged) workstations. The otpasswd consists of a pam module and an user utility. With the utility user manages his "state" file: creates his KEY, manages flags and prints passcards with one-time passwords. PAM module enables (for example) OpenSSH to do an authentication using one-time password with the information from user state file. The program is written in C (C99) and implements OTP as described in "Perfect Paper Passwords" description of which can be found here https://www.grc.com/ppp.htm This program also kind of extends this idea with "salt". OTPasswd is in development. In ChangeLog there's a list of things i'd like to implement before publishing this as version 1.0. Most of features work currently (as of v0.3) but of course - it requires tests. Think of this as a beta software. a. Security concerns -------------------- There are certain security related issues you should be aware of. This program is not intended to replace normal passwords, it's supposed to add a second level of authentication. Therefore an attacker to log into your system must know something you know - a unix password (which he can for example keylog or sniff using e-m radiation of your keyboard's PS/2 communication) and must posess something only you have - a passcard with codes or your mobile phone. Second issue is a DoS attack possible in some configurations. When the attacker repeatedly tries to authenticate he can use up all your printed passcodes and therefore make you unable to login. This can be fixed in several ways: 1) By requesting that the unix password be correctly entered before asking (and therefore using up) a passcode. (See required/requisite difference in PAM description chapter). This will limit the problem to the case when the attacker sniffs your password. He won't be able to login still, but he can perform this DoS attack. Well. That's ok with me. Even better - if he does it, then I know I must change my unix password. 2) By limiting number of trials on another level. For example sshguard can block IP access to SSH after 3 unsuccessful attempts to authenticate. I think that such a security measures should always be enabled no matter if you use OTP or not. Their use would make attacker use a lot more IP addresses (in certain configuration around 23 to skip one passcard) 3) By enabling yourself to receive a next passcode anytime via a secure channel which cannot be blocked by attacker (like SMS). In some scenarios DoS also can be performed. For example if we'd use a free SMS gateway, attacker who'd know our phone number can use it himself to send you few tenths of any messages consuming limit of SMSes/phone number/day. 4) Kind of by enabling dont-skip option. This option is a bit of a problem because we must NEVER allow successful authentication with the same passcode. They must be completely ONE-TIME. Enabling dont-skip causes otpasswd to authenticate like this: a) Read state file, increment passcode counter, store file b) If user authenticates passcode is already incremented and everything is fine. If he fails to authenticate then do the step c: c) Read state file, check if somebody modified this state file in the meantime (second authentication for example). If not - decrement counter and store file. If file was modified nothing is changed, and therefore passcode is securetly skipped. This behaviour *doesn't* solve the problem as you can see, because attacker might use two separate authenticate sessions. This would have to be blocked in some other way (might be implemented in otpasswd one day!) If the attacker will get your previous, used up, passcards he can try to do a brute-force attack on your key to predict future passcodes. Yet, this is kind of a hard thing to do, especially if salting is enabled. See 'Passcode generation algorithm' for details. TODO: What is trusted what's not trusted. Man-in-the middle attacks on SSH. b. Contact ---------- You can contact author with questions, support, praises or curses at bla@thera.be. Any feedback welcomed (even faint one). And no, I don't get a lot of feedback so don't think 'nah, I'wont write anything he's probably pissed at us anyway'. c. History ---------- The creation of this program was inspired by the ppp-pam project (http://code.google.com/p/ppp-pam/). Idea is basically the same. I started development by contributing to ppp-pam, but there was plenty of things to fix, author didn't answer and I just decided I'll be better off rewritting everything from scratch. Projects share some of my code, like locking functions but nothing more. You can kind of thing about otpasswd as a fork of ppp-pam. 2. Installation =============== To install otpasswd and configure it to work with ssh you have to: 0. Have all required dependencies (with headers) 1. Install the package 2. Enable its use in /etc/pam.d 3. Configure ssh to use PAM. 4. Generate keys for user (and print at least one password card) 5. Tweak PAM module configuration So. 0) Package required openssl and gmp libraries and cmake tool (with their -dev packages!). All of these should be available in the repository of your distribution. 1) Check if the package is not in your distribution package manager. If it is - install it as any other software. Otherwise fallback to compilation: $ cd otpasswd $ cmake . # This will generate makefiles $ make # This should compile anything $ make install # This should install binaries into system. Instead of using make install you can also copy two files, PAM module into /lib/security and otpasswd password manager to /usr/bin. There's also examplary pam configuration in example/otpasswd-login this can be copied to /etc/pam.d (which itself won't change anything in your PAM config). 2) See last chapter for detailed information. In short install example/otpasswd-login in /etc/pam.d and change a line in /etc/pam.d/sshd from: auth include system-remote-login to: auth include otpasswd-login 3) In /etc/ssh/sshd_config you should have the following two lines: ChallengeResponseAuthentication yes UsePAM yes 4) To generate key, and display first passcard as fast as possible (so you won't loose ability to login in case you're configuring OTP remotely) you can use: $ otpasswd -k 5) Last line of /etc/pam.d/otpasswd-login has form: auth required pam_otpasswd.so There's a certain set of parameters you can define here: enforced - disallow logon if user doesn't have generated key. (default is to ignore OTP.) secure - disallow dont-skip flag show - always show entered passcodes (ignore user options) noshow - never show passcodes (ignore user options) debug - increase debugging (don't leave this option there for long! as it may leak some passcode information.) retry=X - This configures retry behaviour during single authentication: X: Behaviour: 0 do not retry passcode question (default) 1 retry, but use next passcode from card 2 retry, use the same passcode. and few more are proposed and _might_be_ implemented in future: usechannel=X - Configures a 'second-channel' (for example an email or sms) used for sending user current passcode. X: Behaviour: 0Don't use other channel (default) 1Always use channel 2Use if requested Enabling channel also requires second option: channel=X - X is full-path to script or a program which will be given two parameters on input. User contact information and current prompt + correct passcode. This program operates this 'second-channel' so he might for example send a SMS to the user. 3. Passcode generation algorithm ================================ The heart of the system is Rijndael (AES) cipher, which encrypts 128bit blocks with 256bit key; this operation generated 128bit of data which is used to calculate passcode. Each user during key generation is equipped with this key and 128bit passcode counter. When user authenticates or prints passcard, for each passcode generated the corresponding counter value is encrypted with key: |-------------| | 256 bit key | |-------------| || || || \||/ \/ /-------------\ \ |-----------------| | Rijndael | -------\ | Encrypted value | | Cipher | -------/ | 128 bits | \-------------/ / |-----------------| /\ | /||\ | Repeated division || | by alphabet length. || \ | / || \./ |-----------------| /------------/ | Salt | counter | / Passcode / | 96bit | 32bit | /------------/ |-----------------| This salt needs a bit of explanation. Genuine PPPv3 algorithms doesn't use salt at all - counter is 128bit long. This allows to use over 3.4 * 10^38 passcodes, that is around 4.86 * 10^36 passcards. Nobody needs that much and so this bits would be wasted. Also, an attacker which would be able to keylog your authentication will know corresponding counter value and to predict future passcodes he only lacks the key. Many ciphers were vulnerable to, so called, known-plaintext attacks. Rijndael -- as far as I know -- isn't but it doesn't mean that in future such attack couldn't be discovered. Closing this hole was easy. By generating additionaly 96bits of random data and storing them inside counter value we make attacker impossible task of breaking the key even more impossible. Also brute-force attack on key will take a bit longer. If you had 10^6 of 3GHz machines, being able to test one key in one cycle... you could test 3*10^9*10^6 keys in a second. That would still take you... 1.22 * 10^54 yeeeaaarrrsss. With salt that is more than 10^82 years. 4. About PAM (short talk) ========================= Most application which require password input use PAM. I'll stick to the sshd as an example. SSH when user logs in tries to authenticate him using it's own method - keys. Then, if this method fails it talks with PAM. PAM to see how to authenticate sshd reads /etc/pam.d/sshd. In default Gentoo installation it will contain following lines: auth include system-remote-login account include system-remote-login password include system-remote-login session include system-remote-login This is line-oriented file in which each line tells us what to do. We're interested in "auth" part only, which here - includes configuration from system-remote-login file, which looks like this: auth include system-login And, as you can see, it just reads configuration from yet another file: auth required pam_tally.so onerr=succeed auth required pam_shells.so auth required pam_nologin.so auth include system-auth (account, password, session omitted) Still one more file (system-auth) to look into: auth required pam_env.so auth required pam_unix.so try_first_pass likeauth nullok PAM when authenticating a user will read the lines from top to bottom. pam_tally - reads failures and can do some action according to them pam_shells - checks if user has a valid shell (listed in /etc/shells) pam_nologin - checks if logins were disabled (shows message) pam_env - does something with environment and finally: pam_unix - checks password according to /etc/shadow This is default schema and somewhere there we ought to add our OTP. Easiest approach just modifies the first file: sshd. After all auth entries we just add our pam_otpasswd module. File would look like: auth include system-remote-login # Line added for OTP: auth required pam_otpasswd.so secure account include system-remote-login password include system-remote-login session include system-remote-login This will ask us for OTP after we are asked for our normal unix password regardless if the unix password was correct or not. This can lead to Denial of Service problem when attacker tries to login enough times to use up all our printed passcards. If we have some other security mechanism (like sshguard - which blocks sshd port for people who try the dictionary attacks) it might be perfectly ok. If not, we can change the line with pam_unix.so module from: auth required pam_unix.so try_first_pass likeauth nullok To: auth requisite pam_unix.so try_first_pass likeauth nullok Which will require correct unix password before asking OTP at all. If we don't like to mess with global pam config files (system-auth etc.) we can move all auth lines to sshd file, change this one line and add pam_otpasswd line, which results in following configuration: # Include commented out: #auth include system-remote-login # All auths included in sshd: auth required pam_tally.so onerr=succeed auth required pam_shells.so auth required pam_nologin.so auth required pam_env.so # Changed 'required' to 'requisite': auth requisite pam_unix.so try_first_pass likeauth nullok # Our added line: auth required pam_otpasswd.so secure #Rest account include system-remote-login password include system-remote-login session include system-remote-login This is exactly what is written in our examples/otpasswd-login file. You can place this file in /etc/pam.d, and then edit your ssh to use it in it's auth part: auth include otpasswd-login account include system-remote-login password include system-remote-login session include system-remote-login 5. Demo (Screenshot!) ===================== Everybody loves it, so here is key generation, run by a user who already has some key generated (and some flags toggled: 3-character long passcodes, extended algorithm): %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Cirrus ~ % otpasswd -k ***************************************************** * This will irreversibly erase your previous key * * making all already printed passcards worthless! * ***************************************************** Are you sure you want to continue? (yes/no): yes Your current flags: show dont-skip alphabet-extended (key salted) codelength-3 Do you want to keep them? (yes/no): yes Hint: Move your mouse, cause some disc activity or type on keyboard to make the progress faster. Gathering entropy... OK! ***************************************************** * Print following passcard or at least make a note * * with a few first passcodes so you won't loose * * ability to log into your system! * ***************************************************** Cirrus [1] A B C D E F G H 1: ZKU ;R2 kv_ R-L 3: !w, f%T +q~ M_b 9^3 KcA Po& $h< 4: >vo %(R ak& UF( a|L Y~H A(b zbZ 5: b,i O|, ?b+ VhS Y6F 95/ {\c %MG 6: H/^ t_i Dye k3: 3Mq \7y vz[ +Wk 7: (uU sa3 v\n [%c &5e [mE f"j pq^ 8: Es> ~pa wqo ?C[ !rL Y&O "[4 daT 9: 'x: eE} YwU q|v eyy yp= ;y7 T\- 10: At! mFr GCC @dZ _$_ SeB ^4L |_w Are you ready to start using one-time passwords? (yes/no): yes Key stored! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Example usage: user@host $ ssh user@cirrus Password: Passcode B3 [1]: f%T user@cirrus $ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5. Licensing ============ This README file, examples and the source code of the otpasswd program are all licensed under GNU General Public License version 3. License should be included with the project inside LICENSE file. Copyright notice follows: Copyright (C) 2009 by Tomasz bla Fortuna This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with otpasswd. If not, see .