ONE-TIME AGENT CONFIRMATION (OTAC)

This patch modifies gnome-ssh-askpass to optionally generate a one-time password 
and transmit it via an out-of-band communication channel. If you can read the 
password and enter it back into the gnome-ssh-askpass dialog, ssh-agent is allowed
to continue with the authentication process. 

There are two ways to use the modified gnome-ssh-askpass. The first method 
incrementally increases the security provided by the ssh-agent/gnome-ssh-askpass 
combination. The second allows you to create two fully separated authentication 
factors - the private key and one-time password - without using a specialized hardware 
token.

BACKGROUND:

ssh-agent executes gnome-ssh-askhsss when an OpenSSH client tries to authenticate 
to an SSH server using a private key cached by ssh-agent with the confirm option set.
The gnome-ssh-askpass instance displays a dialog that allows ssh-agent to use the
cached private key when you enter "yes" and/or click the OK button; authentication
can not occur if you don't positively respond to the dialog.

A potential intruder must jump two hurdles to steal your credentials if you use the 
ssh-agent private key confirm option. The first is the ability to access a private 
key by interacting with your ssh-agent via the socket defined by the SSH_AUTH_SOCK 
environmental variable. The second requires access to the your gnome-ssh-askpass 
instance. The two hurdles create a simple but effective two-factor authentication 
system.

However, gnome-ssh-askpass's two factors are vulnerable to an anyone who gains 
user-land access to your workstation. First, both ssh-agent and gnome-ssh-askpass 
instances run in a single location -- your workstation. For instance, a bystander 
immediately gains access to both factors if you simply walk away from your machine 
without setting a screen lock. Second, anyone who breaks into your workstation doesn't 
need a root-shell to steal both factors since both ssh-agent and gnome-ssh-askpass 
communicate through sockets that you own.

INTRODUCTION:

This patch enhances gnome-ssh-askpass's security by giving it an out-of-band
confirmation capability. The modified version optionally generates a secret, called
the one-time confirmation (OTAC) password, and transmits it to a pre-defined
location, typically via e-mail. The valid user must be able to read the secret 
passphrase and give it back to gnome-ssh-askpass. If the two match, gnome-ssh-askpass
allows ssh-agent to finish the private key authentication process (and authenticate
you or not depending on whether your private key matches the public key on the 
remote machine). Otherwise, you can not authenticate. 

How is this different from the original gnome-ssh-askpass? The private key remains
the same as before and is the first factor. You must possess, or have access to,
the private key to start the authentication process. However, you must now obtain 
information created by a separate process - gnome-ssh-askpass - through an 
out-of-band communication channel to complete the authentication process.  The 
potential intruder must now have more than access to your workstation to authenticate 
to the remote server.

HOW IT WORKS:

First you cache a private key(s) in ssh-agent using the confirm option. When you
try to authenticate using the cached key, ssh-agent kicks off the patched 
gnome-ssh-askpass. If you set SSH_OTAC_FIFO to some non-null value, 
gnome-ssh-askpass generates a random string, called the OTAC password and prints it
to the named pipe (FIFO) defined by SSH_OTAC_FIFO. An independent process reads
the OTAC password from the FIFO and transmits it to a pre-defined location.

For instance, run the ssh-otac-fifo.pl Perl script in the background (bundled with
this patch). It reads the OTAC password from the FIFO and e-mails it to your pager,
cell-phone or e-mail account. You enter the OTAC password into the 
gnome-ssh-askpass dialog once your receive it. The public-key authentication
process is allowed to proceed if the two strings match (but the private key still
has to decrypt the challenge encrypted by the public key); authentication can not
occur if the two don't match.

The following list describes two OTAC-based two-factor authentication scenarios.
The first is the easiest to implement but less secure because it doesn't physically
separate both factors. The second scenario achieves better security, at the cost of
additional complexity, by placing the two factors on separate machines. (Other 
scenarios are possible. For instance, the second scenario can be a front-end to a 
key repository. However, this hybrid approach requires socket forwarding and is
beyond the scope of this README.)

1.   Local confirmation:    You cache a private key in a local ssh-agent instance
using the confirm option. When you try to authenticate to the remote machine using
the cached key, ssh-agent sees that the confirm option is set and executes 
gnome-ssh-askpass. If the gnome-ssh-askpass instance sees that SSH_OTAC_FIFO exists,
it generates an OTAC password and passes it to ssh-otac-fifo.pl via a FIFO defined 
by SSH_OTAC_FIFO. The ssh-otac-fifo.pl script, running in the background, reads the
OTAC password from the FIFO and e-mails it to you. If you can read the OTAC password,
you enter it in the gnome-ssh-askpass dialog and are authenticated if it matches the
original. 

The advantage of the local confirmation scenario is simplicity. You only have to
run ssh-otac-fifo.pl on your local workstation, and place your public key in your
authorized_keys file on the remote machine. It's disadvantage is both factors exist 
on one machine, your workstation. Local confirmation achieves incrementally greater 
security over the un-patched gnome-ssh-askpass by passing the OTAC password to 
ssh-otac-fifo.pl through a FIFO owned by root. The potential intruder must work harder 
to gain elevated privileges before stealing the second factor.

2.   Remote confirmation:   This scenario relies on a two-stage authentication 
process, using two private keys. The first stage uses a locally-stored private key 
to non-interactively authenticate to the remote machine. That non-interactive
connection kicks off the second stage, which uses a second private key stored on the
remote machine to make an interactive connection to the remote machine. The second
stage starts an ssh-agent instance and caches the second key with its confirmation 
option set. This stage continues by making a local and interactive SSH connection to
and from the remote machine, which kicks off gnome-ssh-askpass. This instance of 
gnome-ssh-askpass generates and transmits an OTAC password. The second stage run on 
the remote machine and is completely separate from your local workstation as is the
OTAC password it generates and transmits.

A little more detail: the first, local private key is tied to a series of shell
commands on the remote machine defined by the "command=" option in your
authorized_keys file. Authenticating to the remote machine executes the following
processes: start an instance of ssh-agent, cache the second private key, with the
confirm option set, and make a second, interactive SSH connection to the loopback
interface on remote machine. When ssh-agent sees the confirm option set, it kicks
off gnome-ssh-askpass. gnome-ssh-askpass generates and transmits an OTAC password
while also opening a dialog that's displayed on your workstation. You authenticate
by entering the correct OTAC password in the dialog.

The advantage of remote confirmation is total, physical separation of both factors.
First, you need access to your private key to start the process. However, once you
make that initial connection, the OTAC password is generated and delivered from the
remote machine. You must possess the designated physical device if you choose to
receive the OTAC password via cell phone or pager; these devices are not, however,
specialized and difficult to obtain like hardware tokens, they're ubiquitous and
cheap. The disadvantage is it requires you to configure each remote machine with
the modified gnome-ssh-askpass and configure the authorized_keys file.

EXAMPLES:

The following examples show how to use both scenarios.

Notes: 

These instructions were written using two Fedora 8 machines, where gnome-ssh-askpass 
lives in /usr/libexec/openssh; other distributions like Ubuntu use /usr/lib/openssh.

These instructions assume you've stored the patches and scripts in you home directory 
and OpenSSH in /usr/local/openssh-4.7p1. 

Both examples, refer to your local workstation, that one you're working from, as
machineA and the remote machine you're connecting/authenticating to as machineB. 

You have to be able to execute the configuration instructions as Root or via sudo.

Example 1: local confirmation scenario

1.  Log into machineA

2.  Set the SSH_OTAC_FIFO environmental variable. 
        export SSH_OTAC_FIFO=/tmp/ssh-otac.fifo 

3.  Patch and install the gnome-ssh-askpass2.c program    
    (assume /usr/local/openssh-4.7p1)
        cd /usr/local/openssh-4.7p1/contrib 
        patch -p0 < ~/gnome-ssh-askpass2.c.patch 
        make gnome-ssh-askpass2 
        sudo cp gnome-ssh-askpass2 /usr/libexec/openssh/gnome-ssh-askpass 

4. Install and start the ssh-otac-fifo.pl script
        cp ~/ssh-otac-fifo.pl /usr/local/bin 
        /usr/local/bin/ssh-otac-fifo.pl you@someplace.com 

5. Generate a public/private key-pair
        cd ~/.ssh 
        ssh-keygen -t rsa -f otac-machineB -C otac-B

6. Copy the newly generated public key into you authorized_keys file  on machineB
        cat otac-machineB.pub | ssh paul@machineB "cat >> ~/.ssh/authorized_keys"

7. Start an ssh-agent instance and cache the newly generated private key using the
   confirm option
        eval `ssh-agent` 
        ssh-add -c otac-machineB

8. Connect to the remote machine using using the cached private key.
        ssh machineB

        Here's what happens at this point on machineA: 
        A. ssh asks ssh-agent to decrypt the challenge sent from sshd on machineB 
        B. ssh-agent launches gnome-ssh-askpass because the cached private key has
           confirmation set 
        C. gnome-ssh-askpass generates an OTAC password 
        D. gnome-ssh-askpass passes the OTAC password to the FIFO designated by the
           SSH_OTAC_FIFO
        E. gnome-ssh-askpass opens a dialog on machineA
        F.  ssh-otac-fifo.pl reads the OTAC password from the FIFO
        G. ssh-otac-fifo.pl e-mails the OTAC password to your e-mail account, pager,
           or cell phone 

9. You read the OTAC password from the designated channel

10. You enter the OTAC password into the gnome-ssh-askpass dialog

You're authenticated if gnome-ssh-askpass matches the OTAC password you entered
with the original.

11. (OPTIONAL) You can remove password authentication on machineB once you
    authenticate. 
        export SSH_OTAC_FIFO=/tmp/ssh-otac.fifo 
        sudo /etc/init.d/sshd reload 

Example 2: remote confirmation scenario

In this example, the OTAC process occurs on the remote machine, which is also the
one you want to authenticate to.

1.  Log into machineA: 

2.  Generate a public/private key-pair. 
        cd ~/.ssh 
        ssh-keygen -t rsa -f otac-machineB -C otac-B
        Enter a passphrase when prompted

3.  Copy the otac-B.pub public key from machineA to your authorized_keys file on
    machineB. 
        cat otac-machineB.pub | ssh paul@B "cat >> ~/.ssh/authorized_keys"

4.  Log into machineB:

5.  Modify the ssh server configuration to accept the SSH_OTAC_FIFO variable. 
        sudo echo "AcceptEnv SSH_OTAC_FIFO" >> /etc/ssh/sshd_config 
        sudo /etc/init.d/sshd reload 

(We need to explicitly send the SSH_OTAC_FIFO variable from machineA to machineB
because the stage 1, of 2, connection does not start an interactive session so we
don't have a chance to define SSH_OTAC_FIFO via the shell.)

6.  Install and start the ssh-otac-fifo.pl script
        cp ~/ssh-otac-fifo.pl /usr/local/bin
        /usr/local/bin/ssh-otac-fifo.pl paul@someaddr.com 

7.  Patch and install the gnome-ssh-askpass2.c program  
    (assume /usr/local/openssh-4.7p1). 
        cd /usr/local/openssh-4.7p1/contrib 
        patch -p0 < ~/gnome-ssh-askpass2.c.patch 
        make gnome-ssh-askpass2 
        sudo cp gnome-ssh-askpass2 /usr/libexec/openssh/gnome-ssh-askpass 

8.  Generate the second public/private key-pair that will make the second
    connection on the loopback interface. 
        cd ~/.ssh 
        ssh-keygen -t rsa -f otac-loopback -C otac-loopback 
        Do not enter a passphrase

9. Copy the newly created otac-loopback.pub public key into the authorized_keys
   file. 
        cat otac-loopback.pub >> authorized_keys 

10. Modify the first key's - otac-machineB - entry in authorized_keys so it can
start a second, internal connection using the otac-loopback key. Do this by 
pre-pending the "command=" option to the public key entry.

The command/key combination looks similar to the following:

command="eval `ssh-agent`; ssh-add -c ~/.ssh/otac-loopback; ssh -X -o sendenv=SSH_OTAC_FIFO localhost; ssh-agent -k" ssh-rsa AAAAB3NzaC1yc2EAAAABIw ...many many characters... BU9rcQ== otac-remote 
 
        The commands designated in the authorized_keys file perform the following
      functions: 
        a. eval `ssh-agent`  Create an ssh-agent instance 
        b. ssh-add -c ...    Caches the otac-loopback key to ssh-agent using the
           confirm option 
        c. ssh -X -o ...     Makes an interactive SSH connection to the loopback
           interface from and to remote machineB using the private key cached by 
           ssh-agent. This connection specifies X forwarding and sends the
           SSH_OTAC_FIFO environmental variable to the ssh server. 
        d. ssh-agent -k      Stops the ssh-agent instance when you finish your
           session (logout from machineA) 

Back on machineA: 

11.  Set the SSH_OTAC_FIFO environmental variable
        export SSH_OTAC_FIFO=/tmp/ssh-otac.fifo


12. Connect to the remote machine using the private key stored on machineA
        ssh -X -i ~/.ssh/ssh-machineB -o sendenv=SSH_OTAC_FIFO machineB

        What happens on machineB: 
        A. the ssh connection from machineA is authenticated using the first private
         key - ssh-machineB
        B. sshd on machineB executes the commands bound to the first public key in
           the authenticated_keys file on machineB 
        C. the commands (from B) launch ssh-agent, caches the second private key
           using the confirm option and makes a second ssh connection to the loopback
           interface 
        D. ssh-agent launches gnome-ssh-askpass 
        E. gnome-ssh-askpass generates the OTAC password 
        F. gnome-ssh-askpass passes the OTAC password to the FIFO designated by the
           SSH_OTAC_FIFO variable
        G. gnome-ssh-askpass opens a dialog, which you see on machineA because you're
           forwarding X 
        H. ssh-otac-fifo.pl reads the OTAC password 
        I. ssh-otac-fifo.pl e-mails the OTAC password to your e-mail account, pager,
           or cell phone 

13. Read the OTAC password from whatever channel you use and type it into the
    gnome-ssh-askpass dialog. 

If the OTAC password you enter into the dialog matches the original, you are
authenticated. 

14. (OPTIONAL) You can remove password authentication on machineB once you
     authenticate. 
        export SSH_OTAC_FIFO=/tmp/ssh-otac.fifo 
        sudo /etc/init.d/sshd reload 

In this example, the second factor is generated on the remote machine (B) and sent
through a channel that an intruder who has completely compromised the machine you
are working from (A) can never use as long as you are in possession of the
communication channel such as a cell phone. 


SUMMARY:

This modification allows one to create a true two-factor authentication system. The
factors are the private key, or access to the key, and the OTAC password delivered
via an out-of-band channel. You can create the channel without using a traditional
hardware token by using a simple e-mail account, pager or cell-phone.

FUTURE:

Another way to gain two, separate authentication factor would be to add a post 
authentication option sshd that generates and transmit a one-time password. sshd_config
could be modified to add an OTAC feature to the AllowUsers option. If set, sshd would
authenticate as normal (password, public-key, etc.), generate an OTAC password and write
it to a FIFO. An external process reads the password and transmits it to the designated
location. The user is authenticated if the user can read and write the password back to 
sshd. This system would be simpler to configure than one governed by gnome-ssh-askpass, but
would require modifying the openssh code base.

TODO:

1. Create a better random number salt.

2. Make the named pipe defined by SSH_OTAC_FIFO writable by the user but readable
   by only root. 

3. Allow non-graphical interaction.

4. Add logic to generate an OTAC password that a user can also compute. This option
removes the need for the out-of-band communication channel. For instance, the
remote server and user agree on two PINs (one two-digit and one four-digit). The
user asks to authenticate to the remote machine. The remote machine generates the
secret using a formula like: S=date^PIN1 mod(PIN2). The user generates the same
secret using a simple calculator and enters it into gnome-ssh-askpass dialog.
Authentication occurs if the two match (the server generates and compares all
values a minute or two before and after the current time). The intruder must solve
for two unknowns within a short window of a couple of minutes to break this system.
