coding, hacking, startups, computer security, technology and more

Two Factor Authentication With OpenSSH on FreeBSD 7.0

With PCI compliance regulations tightening up, two factor authentication is becoming more and more important. Before I begin let me just say that I was looking for something which was easy to implement and easy to maintain. What I was after was simple, I just wanted SSH to require a password as well as a publickey and access would not be granted unless BOTH authentication methods were successful.

After much searching for options I discovered a patch which was created by some of the folks over at mindrot.org. Unfortunately many of the patches listed on this thread were out of date and the latest patch would not cleanly apply to the OpenSSH_4.5p1 sources in /usr/src.  After a bit of tinkering I managed to get a patch which applied without any problems.

So.. here's the procedure:

Firstly, ensure your sources are up to date, use cvsup if neccessary. My patch applies to the RELENG_7_0 sources without any issues.  Once your sources are up to date, grab a copy of my modified patch:

[root@orion] (~): cd /usr/src/crypto/openssh/
[root@orion] (/usr/src/crypto/openssh): fetch http://jerrywalsh.org/files/openssh-two-factor-auth.patch
openssh-two-factor-auth.patch                 100% of   22 kB   21 kBps
[root@orion] (/usr/src/crypto/openssh): patch < openssh-two-factor-auth.patch
--snip snip--
Patching file sshd_config.5 using Plan A...
Hunk #1 succeeded at 524 with fuzz 1 (offset -1 lines).
Hunk #2 succeeded at 734 with fuzz 2 (offset -66 lines).

No compilation is done from this directory, it is all done from the src/secure directory. The separation between src/contrib and src/crypto is the result of an old USA law, which made these sources export controlled, so they had to be kept separate. Anyway, moving along, now that we've applied the patch we'll need to recompile SSH:

[root@orion] (/usr/src/crypto/openssh): cd /usr/src/secure/ && make clean && make && make install
===> lib (all)
===> lib/libcrypto (all)
cc -O2 -fno-strict-aliasing -pipe -O2 -fno-strict-aliasing -pipe -s  -DTERMIOS -DANSI_SOURCE ..
--snip snip--

This will take a little while as there's a bunch of other stuff in here which will also get compiled. Once it's completed the patched binaries will have been installed. We're not just done quite yet thou...

As you'll see from the mindrot.org link I mentioned earlier, this patch does not support privilegeseparation and after a bunch of trials and tests I discovered you also need to disable PAM support via sshd_config.  Please understand that by disabling privilegeseparation you may be introducing a potential security issue if at some point in the future a vulnerability is discovered and you leave your daemon unpatched against it. For me thou, the benefits provided by this patch far outweight this issue and this combined with the fact that I perform regular patching anyway makes it a non issue. So, let's modify the UsePAM and UsePrivilegeSeparation directives in our sshd_config:

[root@orion] (/usr/src/secure): sed -i '.old' -e ' \
  /^#UsePAM/ s/.*(UsePAM).*/1 no/ \
  /^#UsePrivilegeSeparation/ s/.*(UsePrivilegeSeparation).*/1 no/' \

Finally, we need to specify our newly added configuration directives: RequiredAuthentications1 and RequiredAuthentications2. We use these directives to tell SSH that we want to require BOTH a password AND a publickey - either one of these authentication methods will not be enough to grant access to the machine.

[root@orion] (/usr/src/secure): egrep -q '^RequiredAuthentications1' /etc/ssh/sshd_config || \
        echo "RequiredAuthentications1 password" >> /etc/ssh/sshd_config

[root@orion] (/usr/src/secure): egrep -q '^RequiredAuthentications2' /etc/ssh/sshd_config || \
        echo "RequiredAuthentications2 publickey" >> /etc/ssh/sshd_config

Finally, we need to restart sshd in order for these options and our newly compiled ssh daemon to take effect:

[root@orion] (/usr/src/secure): /etc/rc.d/sshd restart
Stopping sshd.
Starting sshd.
[root@orion] (/usr/src/secure):

Now, this bit is important! Open up a NEW connection to the machine and ensure you can login OK - remember at this point you will need to have your publickey in place, otherwise will you not be able to access the shell!

Assuming you've done everything right at this point connecting via SSH will act a little differently now:

Authenticating with public key "JW" from agent
Authenticated with partial success.
jw@orion's password:
Last login: Thu Nov 13 19:01:40 2008 from
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.  All rights reserved.

FreeBSD 7.0-RELEASE-p5 (ORION) #1: Tue Nov 11 15:38:18 UTC 2008

[jw@orion] (~):

Note the "Authenticated with partial success" line above - congratulations! You've just added two factor authentication to OpenSSH!

I hope you found this guide useful, I know if I had found something like this I'd be very thankful! ;)

Until next time..

EDIT: Brandon Nolte kindly has created a rhel5 package that includes this two-factor authentication patch.