This is a multi-part message in MIME format.
--------------060907070609000803050102
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

The patch (against 4.7p1) modifies gnome-ssh-askpass to optionally
generate a one-time
password and transmits it to the user 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
incrementally increases
the security provided by the traditional 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. Both are
described in the attached
README.

--------------060907070609000803050102
Content-Type: text/x-patch;
name="gnome-ssh-askpass2.c.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="gnome-ssh-askpass2.c.patch"

--- gnome-ssh-askpass2.c.orig 2003-11-21 05:48:56.000000000 -0700
+++ gnome-ssh-askpass2.c 2007-11-01 10:54:11.000000000 -0600
@@ -38,6 +38,9 @@

#define GRAB_TRIES 16
#define GRAB_WAIT 250 /* milliseconds */
+#define OTAC_LEN 4 /* number of characters in otac passphrase */
+#define OTAC_FIFO_LEN 128 /* number of characters in otac passphrase */
+

/*
* Compile with:
@@ -84,7 +87,7 @@
}

static int
-passphrase_dialog(char *message)
+passphrase_dialog(char *message, char *otac_passphrase, char *otac_fifo)
{
const char *failed;
char *passphrase, *local;
@@ -163,17 +166,32 @@
/* Report passphrase if user selected OK */
passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
if (result == GTK_RESPONSE_OK) {
- local = g_locale_from_utf8(passphrase, strlen(passphrase),
- NULL, NULL, NULL);
- if (local != NULL) {
- puts(local);
- memset(local, '\0', strlen(local));
- g_free(local);
- } else {
- puts(passphrase);
- }
+ if (otac_fifo) {
+ if (strcmp(otac_passphrase,passphrase)==0) {
+ puts("yes");
+ } else {
+ puts("no");
+ }
+ } else {
+ local = g_locale_from_utf8(passphrase, strlen(passphrase),
+ NULL, NULL, NULL);
+ if (local != NULL) {
+ puts(local);
+ memset(local, '\0', strlen(local));
+ g_free(local);
+ } else {
+ puts(passphrase);
+ }
+ }
+
}

+ /* Zero otac passphrase in memory */
+ memset(otac_passphrase, '\b', strlen(otac_passphrase));
+ gtk_entry_set_text(GTK_ENTRY(entry), otac_passphrase);
+ memset(otac_passphrase, '\0', strlen(otac_passphrase));
+ g_free(otac_passphrase);
+
/* Zero passphrase in memory */
memset(passphrase, '\b', strlen(passphrase));
gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
@@ -198,11 +216,55 @@
return (-1);
}

+/* generate the one-time agent confirm password */
+char *
+gen_otac_passphrase(int otac_length)
+{
+ int i,ran,nchars=52;
+ char cpool[52]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX YZ";
+ char *otac_passphrase;
+
+ /* use random # to select characters
+ to build one-time passphrase with them */
+
+ srandom(time(0));
+ otac_passphrase=malloc(otac_length+1);
+ for (i=0;i + ran = random();
+ otac_passphrase[i]=cpool[ran%nchars];
+ }
+ strncat(otac_passphrase,"",1);
+
+ return(otac_passphrase);
+}
+
+static void
+write_to_fifo (const char *otac_passphrase,const char *otac_fifo)
+{
+ FILE *out;
+
+ if ( (out=fopen(otac_fifo,"w")) == NULL) {
+ mkfifo(otac_fifo, 0660);
+ out=fopen(otac_fifo,"w");
+ }
+ fflush(out);
+ fprintf(out,"One-time agent confirm: %s\n",otac_passphrase);
+ fclose(out);
+}
+
int
main(int argc, char **argv)
{
- char *message;
- int result;
+ char *message,*passphrase,*otac_passphrase,*otac_fifo;
+ int result,otac_length=OTAC_LEN;
+
+ otac_fifo=malloc(otac_length);
+ otac_fifo=getenv("SSH_OTAC_FIFO");
+ if (otac_fifo) {
+ otac_passphrase=malloc(otac_length+1);
+ otac_passphrase=gen_otac_passphrase(otac_length);
+ write_to_fifo(otac_passphrase,otac_fifo);
+ }

gtk_init(&argc, &argv);

@@ -213,8 +275,7 @@
}

setvbuf(stdout, 0, _IONBF, 0);
- result = passphrase_dialog(message);
+ result = passphrase_dialog(message,otac_passphrase,otac_fif o);
g_free(message);
-
return (result);
}

--------------060907070609000803050102
Content-Type: text/plain;
name="README"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline;
filename="README"

´╗┐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:

When an OpenSSH client tries to authenticate to an SSH server using a private key
cached by ssh-agent with the confirm option set, ssh-agent runs gnome-ssh-askpass.
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.

An intruder must jump two hurdles to steal your connection 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, the gnome-ssh-askpass two-factor system is 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, on your workstation. For
instance, a bystander will immediately gain access to both factors if you simply
walk away from your machine without setting a screen lock. Second, an intruder 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 and
give it back to gnome-ssh-askpass. If the two secrets match, gnome-ssh-askpass
allows ssh-agent to finish the private key authentication process. Otherwise, you
can not authenticate.

How is this different from the original gnome-ssh-askpass? Well, the private key
remains the same as before and is the first factor. You must possess, or have
access to, the key to start the authentication process. However, you now must
obtain information through an out-of-band communication channel to finish 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 completely separating both factors. (Other scenarios are
possible. For instance, the second scenario can be a front-end to a key repository.
However, this hybrid configuration needs its own 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. The gnome-ssh-askpass instance sees that SSH_OTAC_FIFO is set,
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. You read the OTAC password,
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. This method'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 uses 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 another private key stored on the
remote machine to make an interactive connection to the remote machine. The purpose
of the second stage is to cache the second key in ssh-agent with confirmation set
in order to run gnome-ssh-askpass. This instance of gnome-ssh-askpass runs 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.

TODO:

1. Create a better random number salt.

2. Allow non-graphical interaction.

3. 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.

--------------060907070609000803050102
Content-Type: text/plain;
name="ssh-otac-fifo"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="ssh-otac-fifo"

#!/usr/bin/perl

# ssh-otac-fifo
# Copyright 2007 Paul Sery
# License: GPL

#
# Background: if ssh-add caches a private key to ssh-agent using the confirm (-c) option,
# then ssh-agent will wait for the key to be confirmed before allowing the key to be used
# authenticate an ssh session. ssh-agent calls gnome-ssh-askpass2 if the GNOME... environmental
# variable is set. The gnome-ssh-askpass2 displays a dialog and confirms use of the key if you
# either click the OK button, or type "yes" and click the OK button.
#
# This script reads a one-time agent confirm string (password) from a fifo
# and emails it to the designated user. You then enter the string in the
# gnome-ssh-askpass2 dialog. If the string matches the one that gnome-ssh-askpass2
# generated (and wrote to the fifo), then gnome-ssh-askpass2 writes "yes" to stdout.
#

use warnings;
use strict;

my $recipient;
my $debug;

while ($#ARGV >= 0) {
if ($ARGV[0] eq "-d") {
$debug=1;
print "Debug on\n";
}
if ($ARGV[0] ne "-d") {
$recipient=$ARGV[0];
print "Recipient: $recipient\n";
}
shift @ARGV;
}

if (!$recipient) {
print "No reciepient specified\n";
exit;
}



# Don't fork if debug variable set
# (use fork to allow parent to create child process which act as a daemon)
if ($debug) {
main_loop($debug);
} else {
if (fork()) {
exit 0;
} else {
main_loop($debug);
}
}


sub main_loop {
my ($debug)=shift;

my $fifo="/tmp/ssh-otac.fifo";
$fifo = $ENV{'SSH_OTAC_FIFO'} if ( exists $ENV{'SSH_OTAC_FIFO'} );
print "[ssh-otac-fifo.pl] FIFO: $fifo\n" if $debug;

unless (-p $fifo) { system("mkfifo -m 0666 $fifo"); }
open(OUT,"< $fifo") or die "can't open $fifo: $!";
while (1) {
while ( ) {
chomp;
print "[ssh-otac-fifo.pl] OTAC: $_\n" if $debug;
exit if ($_ eq 'END');
put_otac($debug,$recipient,$_);
}
sleep 1;
}
close OUT;
}


sub put_otac {
my ($debug)=shift;
my ($recipient)=shift;
my ($otac)=shift;

$otac=(split /:/,$otac)[1];
if ($debug) {
print "[ssh-otac-fifo.pl] OTAC: $otac\n";
} else {
my $mail = "/bin/mail -s 'OTAC: $otac' $recipient";
open(MAIL, "|$mail") or die "Cannot open $mail: $!";
print MAIL "\t\t$otac\n";
close MAIL;
}
}


--------------060907070609000803050102
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/li...enssh-unix-dev

--------------060907070609000803050102--