Package: openssh
Version: 1:5.1p1-5
Severity: wishlist

Hi,

Fedora provides an patch at
https://cvs.fedoraproject.org/viewvc/F-12/openssh/openssh-5.3p1-nss-keys.patch?revision=1.1&view=markup&sortby=rev
that use keys from the common mozilla security framework (please see
http://fedoraproject.org/wiki/FedoraCryptoConsolidation for the
background). I have tested these patches with an pkcs11-smartcard
which currently can't be used in openssh and they work for me (only
difference for Debian is that the include headers are in different
directories, and the obvious changes for debian/{rules,control,copyright}).

As these patches are provided by Fedora / RedHat there is also some
security support (and I assume RedHat will try to push them upstream
as well). Would be great if this patch could be accepted.


Cheers,
Andi
diff -u openssh-5.1p1/key.h openssh-5.1p1/key.h
--- openssh-5.1p1/key.h
+++ openssh-5.1p1/key.h
@@ -29,12 +29,18 @@
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include <keyhi.h>
+#endif
+
 typedef struct Key Key;
 enum types {
        KEY_RSA1,
        KEY_RSA,
        KEY_DSA,
        KEY_NULL,
+       KEY_NSS,
        KEY_UNSPEC
 };
 enum fp_type {
@@ -49,16 +55,30 @@
 
 /* key is stored in external hardware */
 #define KEY_FLAG_EXT           0x0001
+#define KEY_FLAG_NSS           0x0002
+
+#ifdef HAVE_LIBNSS
+typedef struct NSSKey NSSKey;
+struct NSSKey {
+       SECKEYPrivateKey *privk;
+       SECKEYPublicKey *pubk;
+};
+#endif
 
 struct Key {
        int      type;
        int      flags;
        RSA     *rsa;
        DSA     *dsa;
+#ifdef HAVE_LIBNSS
+       NSSKey  *nss;
+#endif
 };
 
 Key            *key_new(int);
 Key            *key_new_private(int);
+Key            *key_new_nss(int);
+Key            *key_new_nss_copy(int, const Key *);
 void            key_free(Key *);
 Key            *key_demote(const Key *);
 int             key_equal(const Key *, const Key *);
diff -u openssh-5.1p1/configure openssh-5.1p1/configure
--- openssh-5.1p1/configure
+++ openssh-5.1p1/configure
@@ -714,6 +714,7 @@
 PROG_TAIL
 INSTALL_SSH_PRNG_CMDS
 OPENSC_CONFIG
+LIBNSS
 PRIVSEP_PATH
 xauth_path
 STRIP_OPT
@@ -1353,6 +1354,7 @@
   --with-opensc[=PFX]     Enable smartcard support using OpenSC (optionally in 
PATH)
   --with-selinux          Enable SELinux support
   --with-kerberos5=PATH   Enable Kerberos 5 support
+  --with-nss   Enable NSS support
   --with-privsep-path=xxx Path for privilege separation chroot 
(default=/var/empty)
   --with-xauth=PATH       Specify path to xauth program
   --with-mantype=man|cat|doc  Set man page type
@@ -27726,6 +27728,170 @@
 fi
 
 
+# Check whether user wants NSS support
+LIBNSS_MSG="no"
+
+# Check whether --with-nss was given.
+if test "${with_nss+set}" = set; then
+  withval=$with_nss;  if test "x$withval" != "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBNSS 1
+_ACEOF
+
+               LIBNSS_MSG="yes"
+               CPPFLAGS="$CPPFLAGS -I/usr/include/nss -I/usr/include/nspr"
+
+for ac_header in pk11pub.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, 
rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the 
preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the 
compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be 
compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing 
prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite 
headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf 
documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But 
Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be 
Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the 
preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" 
>&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler 
will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take 
precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-...@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+               LIBS="$LIBS -lnss3"
+       fi
+
+fi
+
+
 # Looking for programs, paths and files
 
 PRIVSEP_PATH=/var/empty
@@ -29790,6 +29956,7 @@
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
 OPENSC_CONFIG!$OPENSC_CONFIG$ac_delim
+LIBNSS!$LIBNSS$ac_delim
 PRIVSEP_PATH!$PRIVSEP_PATH$ac_delim
 xauth_path!$xauth_path$ac_delim
 STRIP_OPT!$STRIP_OPT$ac_delim
@@ -29804,7 +29971,7 @@
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 13; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 14; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
@@ -30281,6 +30448,7 @@
 echo "              MD5 password support: $MD5_MSG"
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
+echo "                       NSS support: $LIBNSS_MSG"
 echo "       IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
 echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
 echo "                  BSD Auth support: $BSD_AUTH_MSG"
diff -u openssh-5.1p1/configure.ac openssh-5.1p1/configure.ac
--- openssh-5.1p1/configure.ac
+++ openssh-5.1p1/configure.ac
@@ -3456,6 +3456,20 @@
        ]
 )
 
+# Check whether user wants NSS support
+LIBNSS_MSG="no"
+AC_ARG_WITH(nss,
+       [  --with-nss   Enable NSS support],
+       [ if test "x$withval" != "xno" ; then
+               AC_DEFINE(HAVE_LIBNSS,1,[Define if you want NSS support.])
+               LIBNSS_MSG="yes"
+               CPPFLAGS="$CPPFLAGS -I/usr/include/nss -I/usr/include/nspr"
+               AC_CHECK_HEADERS(pk11pub.h)
+               LIBS="$LIBS -lnss3"
+       fi
+       ])
+AC_SUBST(LIBNSS)
+
 # Looking for programs, paths and files
 
 PRIVSEP_PATH=/var/empty
@@ -4176,6 +4190,7 @@
 echo "              MD5 password support: $MD5_MSG"
 echo "                   libedit support: $LIBEDIT_MSG"
 echo "  Solaris process contract support: $SPC_MSG"
+echo "                       NSS support: $LIBNSS_MSG"
 echo "       IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
 echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
 echo "                  BSD Auth support: $BSD_AUTH_MSG"
diff -u openssh-5.1p1/key.c openssh-5.1p1/key.c
--- openssh-5.1p1/key.c
+++ openssh-5.1p1/key.c
@@ -96,6 +96,54 @@
        return k;
 }
 
+#ifdef HAVE_LIBNSS
+Key *
+key_new_nss(int type)
+{
+       Key *k = key_new(type);
+
+       k->nss = xcalloc(1, sizeof(*k->nss));
+       k->flags = KEY_FLAG_EXT | KEY_FLAG_NSS;
+
+       return k;
+}
+
+Key *
+key_new_nss_copy(int type, const Key *c)
+{
+       Key *k = key_new_nss(type);
+
+       switch (k->type) {
+               case KEY_RSA:
+                       if ((BN_copy(k->rsa->n, c->rsa->n) == NULL) ||
+                               (BN_copy(k->rsa->e, c->rsa->e) == NULL))
+                               fatal("key_new_nss_copy: BN_copy failed");
+                       break;
+               case KEY_DSA:
+                       if ((BN_copy(k->dsa->p, c->rsa->p) == NULL) ||
+                               (BN_copy(k->dsa->q, c->dsa->q) == NULL) ||
+                               (BN_copy(k->dsa->g, c->dsa->g) == NULL) ||
+                               (BN_copy(k->dsa->pub_key, c->dsa->pub_key) == 
NULL))
+                               fatal("key_new_nss_copy: BN_copy failed");
+                       break;
+       }
+               
+       k->nss->privk = SECKEY_CopyPrivateKey(c->nss->privk);
+       if (k->nss->privk == NULL)
+               fatal("key_new_nss_copy: SECKEY_CopyPrivateKey failed");
+
+       k->nss->pubk = SECKEY_CopyPublicKey(c->nss->pubk);
+       if (k->nss->pubk == NULL)
+               fatal("key_new_nss_copy: SECKEY_CopyPublicKey failed");
+       
+       if (c->nss->privk->wincx)
+               k->nss->privk->wincx = xstrdup(c->nss->privk->wincx);
+
+       return k;
+}
+#endif
+
+
 Key *
 key_new_private(int type)
 {
@@ -151,6 +199,19 @@
                fatal("key_free: bad key type %d", k->type);
                break;
        }
+#ifdef HAVE_LIBNSS
+       if (k->flags & KEY_FLAG_NSS) {
+               if (k->nss->privk != NULL && k->nss->privk->wincx != NULL) {
+                       memset(k->nss->privk->wincx, 0,
+                               strlen(k->nss->privk->wincx));
+                       xfree(k->nss->privk->wincx);
+                       k->nss->privk->wincx = NULL;
+               }
+               SECKEY_DestroyPrivateKey(k->nss->privk);
+               SECKEY_DestroyPublicKey(k->nss->pubk);
+               xfree(k->nss);
+       }
+#endif
        xfree(k);
 }
 
diff -u openssh-5.1p1/readconf.c openssh-5.1p1/readconf.c
--- openssh-5.1p1/readconf.c
+++ openssh-5.1p1/readconf.c
@@ -127,6 +127,7 @@
        oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
        oUseBlacklistedKeys,
        oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
+       oUseNSS, oNSSToken,
        oClearAllForwardings, oNoHostAuthenticationForLocalhost,
        oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
        oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@@ -221,6 +222,13 @@
 #else
        { "smartcarddevice", oUnsupported },
 #endif
+#ifdef HAVE_LIBNSS
+       { "usenss", oUseNSS },
+       { "nsstoken", oNSSToken },
+#else
+       { "usenss", oUnsupported },
+       { "nsstoken", oNSSToken },
+#endif
        { "clearallforwardings", oClearAllForwardings },
        { "enablesshkeysign", oEnableSSHKeysign },
        { "verifyhostkeydns", oVerifyHostKeyDNS },
@@ -628,6 +636,14 @@
                charptr = &options->smartcard_device;
                goto parse_string;
 
+       case oUseNSS:
+               intptr = &options->use_nss;
+               goto parse_flag;
+
+       case oNSSToken:
+               charptr = &options->nss_token;
+               goto parse_command;
+
        case oProxyCommand:
                charptr = &options->proxy_command;
 parse_command:
@@ -1104,6 +1120,8 @@
        options->preferred_authentications = NULL;
        options->bind_address = NULL;
        options->smartcard_device = NULL;
+       options->use_nss = -1;
+       options->nss_token = NULL;
        options->enable_ssh_keysign = - 1;
        options->no_host_authentication_for_localhost = - 1;
        options->identities_only = - 1;
@@ -1239,6 +1257,8 @@
                options->no_host_authentication_for_localhost = 0;
        if (options->identities_only == -1)
                options->identities_only = 0;
+       if (options->use_nss == -1)
+               options->use_nss = 0;
        if (options->enable_ssh_keysign == -1)
                options->enable_ssh_keysign = 0;
        if (options->rekey_limit == -1)
diff -u openssh-5.1p1/config.h.in openssh-5.1p1/config.h.in
--- openssh-5.1p1/config.h.in
+++ openssh-5.1p1/config.h.in
@@ -536,6 +536,9 @@
 /* Define to 1 if you have the `nsl' library (-lnsl). */
 #undef HAVE_LIBNSL
 
+/* Define if you want NSS support. */
+#undef HAVE_LIBNSS
+
 /* Define to 1 if you have the `pam' library (-lpam). */
 #undef HAVE_LIBPAM
 
@@ -669,6 +672,9 @@
 /* define if you have pid_t data type */
 #undef HAVE_PID_T
 
+/* Define to 1 if you have the <pk11pub.h> header file. */
+#undef HAVE_PK11PUB_H
+
 /* Define to 1 if you have the `poll' function. */
 #undef HAVE_POLL
 
diff -u openssh-5.1p1/ssh.c openssh-5.1p1/ssh.c
--- openssh-5.1p1/ssh.c
+++ openssh-5.1p1/ssh.c
@@ -104,6 +104,9 @@
 #ifdef SMARTCARD
 #include "scard.h"
 #endif
+#ifdef HAVE_LIBNSS
+#include "nsskeys.h"
+#endif
 
 extern char *__progname;
 
@@ -1241,9 +1244,11 @@
        int i = 0;
        Key *public;
        struct passwd *pw;
-#ifdef SMARTCARD
+#if defined(SMARTCARD) || defined(HAVE_LIBNSS)
        Key **keys;
+#endif
 
+#ifdef SMARTCARD
        if (options.smartcard_device != NULL &&
            options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
            (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) {
@@ -1266,6 +1271,27 @@
                xfree(keys);
        }
 #endif /* SMARTCARD */
+#ifdef HAVE_LIBNSS
+       if (options.use_nss &&
+           options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
+           (keys = nss_get_keys(options.nss_token, NULL, NULL)) != NULL) {
+               int count;
+               for (count = 0; keys[count] != NULL; count++) {
+                       memmove(&options.identity_files[1], 
&options.identity_files[0],
+                           sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
+                       memmove(&options.identity_keys[1], 
&options.identity_keys[0],
+                           sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
+                       options.num_identity_files++;
+                       options.identity_keys[0] = keys[count];
+                       options.identity_files[0] = 
nss_get_key_label(keys[count]);
+               }
+               if (options.num_identity_files > SSH_MAX_IDENTITY_FILES)
+                       options.num_identity_files = SSH_MAX_IDENTITY_FILES;
+               i += count;
+               xfree(keys);
+       }
+#endif /* HAVE_LIBNSS */
+
        if ((pw = getpwuid(original_real_uid)) == NULL)
                fatal("load_public_identity_files: getpwuid failed");
        pwname = xstrdup(pw->pw_name);
diff -u openssh-5.1p1/ssh-add.c openssh-5.1p1/ssh-add.c
--- openssh-5.1p1/ssh-add.c
+++ openssh-5.1p1/ssh-add.c
@@ -44,6 +44,14 @@
 #include <openssl/evp.h>
 #include "openbsd-compat/openssl-compat.h"
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include <secmod.h>
+#include <pk11pub.h>
+#include <keyhi.h>
+#include <cert.h>
+#endif
+
 #include <fcntl.h>
 #include <pwd.h>
 #include <stdarg.h>
@@ -57,6 +65,7 @@
 #include "rsa.h"
 #include "log.h"
 #include "key.h"
+#include "nsskeys.h"
 #include "buffer.h"
 #include "authfd.h"
 #include "authfile.h"
@@ -315,6 +324,128 @@
        return 0;
 }
 
+#ifdef HAVE_LIBNSS
+static char *
+password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+       char **passcache = arg;
+       char *password, *p2 = NULL;
+       char *prompt;
+       
+       if (retry)
+               return NULL;
+       
+       if (asprintf(&prompt, "Enter passphrase for token %s: ",
+               PK11_GetTokenName(slot)) < 0)
+               fatal("password_cb: asprintf failed");
+
+       password = read_passphrase(prompt, RP_ALLOW_STDIN);
+       
+       if (password != NULL && (p2=PL_strdup(password)) == NULL) {
+               memset(password, 0, strlen(password));
+               fatal("password_cb: PL_strdup failed");
+       }
+
+       if (passcache != NULL) {
+               if (*passcache != NULL) {
+                       memset(*passcache, 0, strlen(*passcache));
+                       xfree(*passcache);
+               }
+               *passcache = password;
+       } else {
+               memset(password, 0, strlen(password));
+               xfree(password);
+       }
+       
+       return p2;
+}
+
+static int
+add_slot_keys(AuthenticationConnection *ac, PK11SlotInfo *slot, int add)
+{
+       SECKEYPrivateKeyList *list;
+       SECKEYPrivateKeyListNode *node;
+       char *passcache = NULL;
+       char *tokenname;
+       char **xkeyname = NULL;
+       
+       int count = 0;
+       int i;
+       
+       if (PK11_NeedLogin(slot))
+               PK11_Authenticate(slot, PR_TRUE, &passcache);
+               
+       if ((list=PK11_ListPrivKeysInSlot(slot, NULL, NULL)) == NULL) {
+               return 0;
+       }
+       
+       tokenname = PK11_GetTokenName(slot);
+       
+       for (node=PRIVKEY_LIST_HEAD(list); !PRIVKEY_LIST_END(node, list);
+               node=PRIVKEY_LIST_NEXT(node)) {
+               char *keyname;
+               SECKEYPublicKey *pub;
+               
+               keyname = PK11_GetPrivateKeyNickname(node->key);
+               if (keyname == NULL || *keyname == '\0') {
+                       /* no nickname to refer to */
+                       CERTCertificate *cert;
+                       char *kn;
+                       cert = PK11_GetCertFromPrivateKey(node->key);
+                       if (cert == NULL)
+                               continue;
+                       kn = strchr(cert->nickname, ':');
+                       if (kn == NULL)
+                               kn = cert->nickname;
+                       else
+                               kn++;
+                       keyname = PORT_Strdup(kn);
+                       CERT_DestroyCertificate(cert);
+                       if (keyname == NULL)
+                               continue;
+               }
+               pub = SECKEY_ConvertToPublicKey(node->key);
+               if (pub == NULL) {
+                       fprintf(stderr, "No public key for: %s:%s\n",
+                               tokenname, keyname);
+                       continue; /* not possible to obtain public key */
+               }
+               SECKEY_DestroyPublicKey(pub);
+       
+               if ((count % 10) == 0)  
+                       xkeyname = xrealloc (xkeyname, count + 10, sizeof (char 
*));
+               
+               xkeyname[count++] = keyname;
+       }
+
+       PK11_Logout(slot);
+
+       for (i = 0; i < count; i++) {
+               if (ssh_update_nss_key(ac, add, tokenname, xkeyname[i],
+                       passcache?passcache:"", lifetime, confirm)) {
+                       fprintf(stderr, "Key %s: %s:%s\n",
+                               add?"added":"removed", tokenname, xkeyname[i]);
+               } else {
+                       fprintf(stderr, "Could not %s key: %s:%s\n",
+                               add?"add":"remove", tokenname, xkeyname[i]);
+               }
+               PORT_Free(xkeyname[i]);
+       }
+
+       if (xkeyname != NULL)
+               free (xkeyname);
+
+       if (passcache != NULL) {
+               memset(passcache, 0, strlen(passcache));
+               xfree(passcache);
+       }
+       
+       SECKEY_DestroyPrivateKeyList(list);
+       
+       return count;
+}
+#endif
+
 static void
 usage(void)
 {
@@ -342,6 +473,10 @@
        AuthenticationConnection *ac = NULL;
        char *sc_reader_id = NULL;
        int i, ch, deleting = 0, ret = 0;
+#ifdef HAVE_LIBNSS
+       char *token_id = NULL;
+       int use_nss = 0;
+#endif
 
        /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
        sanitise_stdfd();
@@ -359,7 +494,7 @@
                    "Could not open a connection to your authentication 
agent.\n");
                exit(2);
        }
-       while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) {
+       while ((ch = getopt(argc, argv, "lLcdDnxXe:s:t:T:")) != -1) {
                switch (ch) {
                case 'l':
                case 'L':
@@ -381,6 +516,11 @@
                        if (delete_all(ac) == -1)
                                ret = 1;
                        goto done;
+#ifdef HAVE_LIBNSS
+               case 'n':
+                       use_nss = 1;
+                       break;
+#endif
                case 's':
                        sc_reader_id = optarg;
                        break;
@@ -395,6 +535,11 @@
                                goto done;
                        }
                        break;
+#ifdef HAVE_LIBNSS
+               case 'T':
+                       token_id = optarg;
+                       break;
+#endif
                default:
                        usage();
                        ret = 1;
@@ -408,6 +553,40 @@
                        ret = 1;
                goto done;
        }
+#ifdef HAVE_LIBNSS
+       if (use_nss) {
+               PK11SlotList *slots;
+               PK11SlotListElement *sle;
+               int count = 0;
+               if (nss_init(password_cb) == -1) {
+                       fprintf(stderr, "Failed to initialize NSS library\n");
+                       ret = 1;
+                       goto done;
+               }
+               
+               if ((slots=PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, 
PR_FALSE,
+                       NULL)) == NULL) {
+                       fprintf(stderr, "No tokens found\n");
+                       ret = 1;
+                       goto nss_done;
+               }
+
+               for (sle = slots->head; sle; sle = sle->next) {
+                       int rv;
+                       if ((rv=add_slot_keys(ac, sle->slot, !deleting)) == -1) 
{
+                               ret = 1;
+                       }
+                       count += rv;
+               }
+               if (count == 0) {
+                       ret = 1;
+               }
+nss_done:              
+               NSS_Shutdown();
+               clear_pass();
+               goto done;
+       }
+#endif
        if (argc == 0) {
                char buf[MAXPATHLEN];
                struct passwd *pw;
diff -u openssh-5.1p1/Makefile.in openssh-5.1p1/Makefile.in
--- openssh-5.1p1/Makefile.in
+++ openssh-5.1p1/Makefile.in
@@ -73,7 +73,7 @@
        atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
        monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
        kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
-       entropy.o scard-opensc.o gss-genr.o umac.o kexgssc.o
+       entropy.o scard-opensc.o gss-genr.o umac.o kexgssc.o nsskeys.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
        sshconnect.o sshconnect1.o sshconnect2.o mux.o
diff -u openssh-5.1p1/readconf.h openssh-5.1p1/readconf.h
--- openssh-5.1p1/readconf.h
+++ openssh-5.1p1/readconf.h
@@ -87,6 +87,8 @@
        char   *preferred_authentications;
        char   *bind_address;   /* local socket address for connection to sshd 
*/
        char   *smartcard_device; /* Smartcard reader device */
+       int     use_nss;        /* Use NSS library for keys */
+       char   *nss_token;      /* Look for NSS keys on token */
        int     verify_host_key_dns;    /* Verify host key using DNS */
 
        int     num_identity_files;     /* Number of files for RSA/DSA 
identities. */
diff -u openssh-5.1p1/debian/control openssh-5.1p1/debian/control
--- openssh-5.1p1/debian/control
+++ openssh-5.1p1/debian/control
@@ -2,7 +2,7 @@
 Section: net
 Priority: standard
 Maintainer: Debian OpenSSH Maintainers <debian-...@lists.debian.org>
-Build-Depends: libwrap0-dev | libwrap-dev, zlib1g-dev (>= 1:1.2.3-1), 
libssl-dev (>= 0.9.8-1), libpam0g-dev | libpam-dev, libgtk2.0-dev, libedit-dev, 
debhelper (>= 5.0.22), sharutils, libselinux1-dev [alpha amd64 arm armeb armel 
hppa i386 ia64 lpia m68k mips mipsel powerpc ppc64 s390 sparc], libkrb5-dev | 
heimdal-dev
+Build-Depends: libwrap0-dev | libwrap-dev, zlib1g-dev (>= 1:1.2.3-1), 
libssl-dev (>= 0.9.8-1), libpam0g-dev | libpam-dev, libgtk2.0-dev, libedit-dev, 
debhelper (>= 5.0.22), sharutils, libselinux1-dev [alpha amd64 arm armeb armel 
hppa i386 ia64 lpia m68k mips mipsel powerpc ppc64 s390 sparc], libkrb5-dev | 
heimdal-dev, libnss3-dev, libnspr4-dev
 Standards-Version: 3.7.3
 Uploaders: Colin Watson <cjwat...@debian.org>, Matthew Vernon 
<matt...@debian.org>
 
diff -u openssh-5.1p1/debian/changelog openssh-5.1p1/debian/changelog
--- openssh-5.1p1/debian/changelog
+++ openssh-5.1p1/debian/changelog
@@ -1,3 +1,10 @@
+openssh (1:5.1p1-5~aba+1) unstable; urgency=low
+
+  * Add nss patch from Fedora from
+    
https://cvs.fedoraproject.org/viewvc/F-12/openssh/openssh-5.3p1-nss-keys.patch?revision=1.1&content-type=text%2Fplain&view=co
+
+ -- Andreas Barth <a...@not.so.argh.org>  Fri, 27 Nov 2009 18:40:35 +0000
+
 openssh (1:5.1p1-5) unstable; urgency=low
 
   * Backport from upstream CVS (Markus Friedl):
diff -u openssh-5.1p1/debian/rules openssh-5.1p1/debian/rules
--- openssh-5.1p1/debian/rules
+++ openssh-5.1p1/debian/rules
@@ -82,6 +82,7 @@
 confflags += --with-libedit
 confflags += --with-kerberos5=/usr
 confflags += --with-ssl-engine
+confflags += --with-nss
 ifeq ($(DEB_HOST_ARCH_OS),linux)
 confflags += --with-selinux
 endif
@@ -215,7 +216,7 @@
        dh_testdir
        dh_testroot
        dh_installdebconf
-       dh_installdocs OVERVIEW README README.dns README.tun debian/faq.html 
debian/README.compromised-keys
+       dh_installdocs OVERVIEW README README.dns README.tun debian/faq.html 
debian/README.compromised-keys README.nss
        dh_installchangelogs ChangeLog ChangeLog.gssapi
        install -m644 debian/openssh-client.lintian 
debian/openssh-client/usr/share/lintian/overrides/openssh-client
        dh_strip
only in patch2:
unchanged:
--- openssh-5.1p1.orig/authfd.c
+++ openssh-5.1p1/authfd.c
@@ -626,6 +626,45 @@
        return decode_reply(type);
 }
 
+int
+ssh_update_nss_key(AuthenticationConnection *auth, int add,
+    const char *tokenname, const char *keyname,
+    const char *pass, u_int life, u_int confirm)
+{
+       Buffer msg;
+       int type, constrained = (life || confirm);
+
+       if (add) {
+               type = constrained ?
+                   SSH_AGENTC_ADD_NSS_KEY_CONSTRAINED :
+                   SSH_AGENTC_ADD_NSS_KEY;
+       } else
+               type = SSH_AGENTC_REMOVE_NSS_KEY;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, type);
+       buffer_put_cstring(&msg, tokenname);
+       buffer_put_cstring(&msg, keyname);
+       buffer_put_cstring(&msg, pass);
+
+       if (constrained) {
+               if (life != 0) {
+                       buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);
+                       buffer_put_int(&msg, life);
+               }
+               if (confirm != 0)
+                       buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM);
+       }
+
+       if (ssh_request_reply(auth, &msg, &msg) == 0) {
+               buffer_free(&msg);
+               return 0;
+       }
+       type = buffer_get_char(&msg);
+       buffer_free(&msg);
+       return decode_reply(type);
+}
+
 /*
  * Removes all identities from the agent.  This call is not meant to be used
  * by normal applications.
only in patch2:
unchanged:
--- openssh-5.1p1.orig/ssh-keygen.c
+++ openssh-5.1p1/ssh-keygen.c
@@ -53,6 +53,11 @@
 #include "scard.h"
 #endif
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include "nsskeys.h"
+#endif
+
 /* Number of bits in the RSA/DSA key.  This value can be set on the command 
line. */
 #define DEFAULT_BITS           2048
 #define DEFAULT_BITS_DSA       1024
@@ -501,6 +506,26 @@
 }
 #endif /* SMARTCARD */
 
+#ifdef HAVE_LIBNSS
+static void
+do_nss_download(struct passwd *pw, const char *tokenname, const char *keyname)
+{
+       Key **keys = NULL;
+       int i;
+       
+       keys = nss_get_keys(tokenname, keyname, NULL);
+       if (keys == NULL)
+               fatal("cannot find public key in NSS");
+       for (i = 0; keys[i]; i++) {
+               key_write(keys[i], stdout);
+               key_free(keys[i]);
+               fprintf(stdout, "\n");
+       }
+       xfree(keys);
+       exit(0);
+}
+#endif /* HAVE_LIBNSS */
+
 static void
 do_fingerprint(struct passwd *pw)
 {
@@ -1083,7 +1108,8 @@
        Key *private, *public;
        struct passwd *pw;
        struct stat st;
-       int opt, type, fd, download = 0;
+       int opt, type, fd, download = 1;
+       int use_nss = 0;
        u_int32_t memory = 0, generator_wanted = 0, trials = 100;
        int do_gen_candidates = 0, do_screen_candidates = 0;
        BIGNUM *start = NULL;
@@ -1116,7 +1142,7 @@
        }
 
        while ((opt = getopt(argc, argv,
-           "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
+           "degiqpclnBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
                switch (opt) {
                case 'b':
                        bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
@@ -1156,6 +1182,10 @@
                case 'g':
                        print_generic = 1;
                        break;
+               case 'n':
+                       use_nss = 1;
+                       download = 1;
+                       break;
                case 'P':
                        identity_passphrase = optarg;
                        break;
@@ -1187,10 +1217,10 @@
                case 't':
                        key_type_name = optarg;
                        break;
-               case 'D':
-                       download = 1;
-                       /*FALLTHROUGH*/
                case 'U':
+                       download = 0;
+                       /*FALLTHROUGH*/
+               case 'D':
                        reader_id = optarg;
                        break;
                case 'v':
@@ -1299,6 +1329,17 @@
                        exit(0);
                }
        }
+
+       if (use_nss) {
+#ifdef HAVE_LIBNSS
+               if (download)
+                       do_nss_download(pw, reader_id, identity_file);
+               else
+                       fatal("no support for NSS key upload.");
+#else
+               fatal("no support for NSS keys.");
+#endif
+       }
        if (reader_id != NULL) {
 #ifdef SMARTCARD
                if (download)
only in patch2:
unchanged:
--- openssh-5.1p1.orig/ssh-agent.c
+++ openssh-5.1p1/ssh-agent.c
@@ -80,6 +80,10 @@
 #include "scard.h"
 #endif
 
+#ifdef HAVE_LIBNSS
+#include "nsskeys.h"
+#endif
+
 #if defined(HAVE_SYS_PRCTL_H)
 #include <sys/prctl.h> /* For prctl() and PR_SET_DUMPABLE */
 #endif
@@ -714,6 +718,114 @@
 }
 #endif /* SMARTCARD */
 
+#ifdef HAVE_LIBNSS
+static void
+process_add_nss_key (SocketEntry *e)
+{
+       char *tokenname = NULL, *keyname = NULL, *password = NULL;
+       int i, version, success = 0, death = 0, confirm = 0;
+       Key **keys, *k;
+       Identity *id;
+       Idtab *tab;
+
+       tokenname = buffer_get_string(&e->request, NULL);
+       keyname = buffer_get_string(&e->request, NULL);
+       password = buffer_get_string(&e->request, NULL);
+
+       while (buffer_len(&e->request)) {
+               switch (buffer_get_char(&e->request)) {
+               case SSH_AGENT_CONSTRAIN_LIFETIME:
+                       death = time(NULL) + buffer_get_int(&e->request);
+                       break;
+               case SSH_AGENT_CONSTRAIN_CONFIRM:
+                       confirm = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (lifetime && !death)
+               death = time(NULL) + lifetime;
+
+       keys = nss_get_keys(tokenname, keyname, password);
+       /* password is owned by keys[0] now */
+       xfree(tokenname);
+       xfree(keyname);
+
+       if (keys == NULL) {
+               memset(password, 0, strlen(password));
+               xfree(password);
+               error("nss_get_keys failed");
+               goto send;
+       }
+       for (i = 0; keys[i] != NULL; i++) {
+               k = keys[i];
+               version = k->type == KEY_RSA1 ? 1 : 2;
+               tab = idtab_lookup(version);
+               if (lookup_identity(k, version) == NULL) {
+                       id = xmalloc(sizeof(Identity));
+                       id->key = k;
+                       id->comment = nss_get_key_label(k);
+                       id->death = death;
+                       id->confirm = confirm;
+                       TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+                       tab->nentries++;
+                       success = 1;
+               } else {
+                       key_free(k);
+               }
+               keys[i] = NULL;
+       }
+       xfree(keys);
+send:
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_nss_key(SocketEntry *e)
+{
+       char *tokenname = NULL, *keyname = NULL, *password = NULL;
+       int i, version, success = 0;
+       Key **keys, *k = NULL;
+       Identity *id;
+       Idtab *tab;
+
+       tokenname = buffer_get_string(&e->request, NULL);
+       keyname = buffer_get_string(&e->request, NULL);
+       password = buffer_get_string(&e->request, NULL);
+
+       keys = nss_get_keys(tokenname, keyname, password);
+       xfree(tokenname);
+       xfree(keyname);
+       xfree(password);
+
+       if (keys == NULL || keys[0] == NULL) {
+               error("nss_get_keys failed");
+               goto send;
+       }
+       for (i = 0; keys[i] != NULL; i++) {
+               k = keys[i];
+               version = k->type == KEY_RSA1 ? 1 : 2;
+               if ((id = lookup_identity(k, version)) != NULL) {
+                       tab = idtab_lookup(version);
+                       TAILQ_REMOVE(&tab->idlist, id, next);
+                       tab->nentries--;
+                       free_identity(id);
+                       success = 1;
+               }
+               key_free(k);
+               keys[i] = NULL;
+       }
+       xfree(keys);
+send:
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif /* HAVE_LIBNSS */
+
 /* dispatch incoming messages */
 
 static void
@@ -806,6 +918,15 @@
                process_remove_smartcard_key(e);
                break;
 #endif /* SMARTCARD */
+#ifdef HAVE_LIBNSS
+       case SSH_AGENTC_ADD_NSS_KEY:
+       case SSH_AGENTC_ADD_NSS_KEY_CONSTRAINED:
+               process_add_nss_key(e);
+               break;
+       case SSH_AGENTC_REMOVE_NSS_KEY:
+               process_remove_nss_key(e);
+               break;
+#endif /* SMARTCARD */
        default:
                /* Unknown message.  Respond with failure. */
                error("Unknown message %d", type);
only in patch2:
unchanged:
--- openssh-5.1p1.orig/ssh-dss.c
+++ openssh-5.1p1/ssh-dss.c
@@ -39,6 +39,10 @@
 #include "log.h"
 #include "key.h"
 
+#ifdef HAVE_LIBNSS
+#include <cryptohi.h>
+#endif
+
 #define INTBLOB_LEN    20
 #define SIGBLOB_LEN    (2*INTBLOB_LEN)
 
@@ -57,6 +61,34 @@
                error("ssh_dss_sign: no DSA key");
                return -1;
        }
+#ifdef HAVE_LIBNSS
+       if (key->flags & KEY_FLAG_NSS) {
+               SECItem sigitem;
+               SECItem *rawsig;
+
+               memset(&sigitem, 0, sizeof(sigitem));
+               if (SEC_SignData(&sigitem, (u_char *)data, datalen, 
key->nss->privk,
+                       SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) != 
SECSuccess) {
+                       error("ssh_dss_sign: sign failed");
+                       return -1;
+               }
+               
+               if ((rawsig=DSAU_DecodeDerSig(&sigitem)) == NULL) {
+                       error("ssh_dss_sign: der decode failed");
+                       SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+                       return -1;
+               }
+               SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+               if (rawsig->len != SIGBLOB_LEN) {
+                       error("ssh_dss_sign: unsupported signature length %d",
+                               rawsig->len);
+                       SECITEM_ZfreeItem(rawsig, PR_TRUE);
+                       return -1;
+               }
+               memcpy(sigblob, rawsig->data, SIGBLOB_LEN);
+               SECITEM_ZfreeItem(rawsig, PR_TRUE);
+       } else {
+#endif
        EVP_DigestInit(&md, evp_md);
        EVP_DigestUpdate(&md, data, datalen);
        EVP_DigestFinal(&md, digest, &dlen);
@@ -80,7 +112,9 @@
        BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
        BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
        DSA_SIG_free(sig);
-
+#ifdef HAVE_LIBNSS
+       }
+#endif
        if (datafellows & SSH_BUG_SIGBLOB) {
                if (lenp != NULL)
                        *lenp = SIGBLOB_LEN;
only in patch2:
unchanged:
--- openssh-5.1p1.orig/README.nss
+++ openssh-5.1p1/README.nss
@@ -0,0 +1,36 @@
+How to use NSS tokens with OpenSSH?
+
+This version of OpenSSH contains experimental support for authentication using
+keys stored in tokens stored in NSS database. This for example includes any
+PKCS#11 tokens which are installed in your NSS database.
+
+As the code is experimental and preliminary only SSH protocol 2 is supported.
+The NSS certificate and token databases are looked for in the ~/.ssh
+directory or in a directory specified by environment variable NSS_DB_PATH.
+
+Common operations:
+
+(1) tell the ssh client to use the NSS keys:
+
+       $ ssh -o 'UseNSS yes' otherhost
+       
+       if you want to use a specific token:
+       
+       $ ssh -o 'UseNSS yes' -o 'NSS Token My PKCS11 Token' otherhost
+
+(2) or tell the agent to use the NSS keys:
+
+       $ ssh-add -n
+       
+       if you want to use a specific token:
+       
+       $ ssh-add -n -T 'My PKCS11 Token'
+
+(3) extract the public key from token so it can be added to the
+server:
+
+       $ ssh-keygen -n
+       
+       if you want to use a specific token and/or key:
+       
+       $ ssh-keygen -n -D 'My PKCS11 Token' 'My Key ID'
only in patch2:
unchanged:
--- openssh-5.1p1.orig/authfd.h
+++ openssh-5.1p1/authfd.h
@@ -49,6 +49,12 @@
 #define SSH2_AGENTC_ADD_ID_CONSTRAINED         25
 #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
 
+/* nss */
+#define SSH_AGENTC_ADD_NSS_KEY                 30
+#define SSH_AGENTC_REMOVE_NSS_KEY              31
+#define SSH_AGENTC_ADD_NSS_KEY_CONSTRAINED     32
+
+
 #define        SSH_AGENT_CONSTRAIN_LIFETIME            1
 #define        SSH_AGENT_CONSTRAIN_CONFIRM             2
 
@@ -83,6 +89,8 @@
 int     ssh_lock_agent(AuthenticationConnection *, int, const char *);
 int     ssh_update_card(AuthenticationConnection *, int, const char *,
     const char *, u_int, u_int);
+int     ssh_update_nss_key(AuthenticationConnection *, int, const char *,
+    const char *, const char *, u_int, u_int);
 
 int
 ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16],
only in patch2:
unchanged:
--- openssh-5.1p1.orig/ssh-rsa.c
+++ openssh-5.1p1/ssh-rsa.c
@@ -32,6 +32,10 @@
 #include "compat.h"
 #include "ssh.h"
 
+#ifdef HAVE_LIBNSS
+#include <cryptohi.h>
+#endif
+
 static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
 
 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
@@ -50,6 +54,38 @@
                error("ssh_rsa_sign: no RSA key");
                return -1;
        }
+
+       slen = RSA_size(key->rsa);
+       sig = xmalloc(slen);
+
+#ifdef HAVE_LIBNSS
+       if (key->flags & KEY_FLAG_NSS) {
+               SECItem sigitem;
+               SECOidTag alg;
+
+               memset(&sigitem, 0, sizeof(sigitem));
+               alg = (datafellows & SSH_BUG_RSASIGMD5) ?
+                       SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION :
+                       SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+
+               if (SEC_SignData(&sigitem, (u_char *)data, datalen, 
key->nss->privk,
+                       alg) != SECSuccess) {
+                       error("ssh_rsa_sign: sign failed");
+                       return -1;
+               }
+               if (sigitem.len > slen) {
+                       error("ssh_rsa_sign: slen %u slen2 %u", slen, 
sigitem.len);
+                       xfree(sig);
+                       SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+                       return -1;
+               }
+               if (sigitem.len < slen) {
+                       memset(sig, 0, slen - sigitem.len);
+               }
+               memcpy(sig+slen-sigitem.len, sigitem.data, sigitem.len);
+               SECITEM_ZfreeItem(&sigitem, PR_FALSE);
+       } else {
+#endif
        nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
        if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
                error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
@@ -59,9 +95,6 @@
        EVP_DigestUpdate(&md, data, datalen);
        EVP_DigestFinal(&md, digest, &dlen);
 
-       slen = RSA_size(key->rsa);
-       sig = xmalloc(slen);
-
        ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
        memset(digest, 'd', sizeof(digest));
 
@@ -83,6 +116,9 @@
                xfree(sig);
                return -1;
        }
+#ifdef HAVE_LIBNSS
+       }
+#endif
        /* encode signature */
        buffer_init(&b);
        buffer_put_cstring(&b, "ssh-rsa");
only in patch2:
unchanged:
--- openssh-5.1p1.orig/nsskeys.h
+++ openssh-5.1p1/nsskeys.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2007 Red Hat, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NSSKEYS_H
+#define NSSKEYS_H
+#ifdef HAVE_LIBNSS
+#include <pk11func.h>
+#include <prtypes.h>
+
+int    nss_init(PK11PasswordFunc);
+Key    **nss_get_keys(const char *, const char *, char *);
+char   *nss_get_key_label(Key *);
+/*void  sc_close(void);*/
+/*int   sc_put_key(Key *, const char *);*/
+
+#endif
+#endif
only in patch2:
unchanged:
--- openssh-5.1p1.orig/nsskeys.c
+++ openssh-5.1p1/nsskeys.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#ifdef HAVE_LIBNSS
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+
+#include <nss.h>
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <cert.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "log.h"
+#include "misc.h"
+#include "nsskeys.h"
+#include "pathnames.h"
+
+static char *
+password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+       char *password = arg;
+       if (retry || password == NULL)
+               return NULL;
+       
+       return PL_strdup(password);
+}
+
+int
+nss_init(PK11PasswordFunc pwfn)
+{
+       char *dbpath;
+       char buf[MAXPATHLEN];
+
+       if (NSS_IsInitialized())
+               return 0;
+
+       if ((dbpath=getenv("NSS_DB_PATH")) == NULL) {
+               struct passwd *pw;
+               if ((pw = getpwuid(getuid())) == NULL ||
+                       pw->pw_dir == NULL) {
+                       return -1;
+               }
+               snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
+                           _PATH_SSH_USER_DIR);
+               dbpath = buf;
+       }
+
+       if (NSS_Init(dbpath) != SECSuccess)
+               return -1;
+
+       if (pwfn == NULL) {
+               pwfn = password_cb;
+       }
+
+       PK11_SetPasswordFunc(pwfn);
+       
+       return 0;
+}
+
+static Key *
+make_key_from_privkey(SECKEYPrivateKey *privk, char *password)
+{
+       Key *k;
+       switch (SECKEY_GetPrivateKeyType(privk)) {
+               case rsaKey:
+                       k = key_new_nss(KEY_RSA);
+                       break;
+               case dsaKey:
+                       k = key_new_nss(KEY_DSA);
+                       break;
+               default:
+                       return NULL;
+       }
+       k->nss->pubk = SECKEY_ConvertToPublicKey(privk);
+       if (k->nss->pubk != NULL) {
+               k->nss->privk = SECKEY_CopyPrivateKey(privk);
+       }
+       if (k->nss->privk != NULL) {
+               if (password != NULL) {
+                       k->nss->privk->wincx = xstrdup(password);
+               }
+               return k;
+       }
+       key_free(k);
+       return NULL;
+}
+
+static Key **
+add_key_to_list(Key *k, Key **keys, size_t *i, size_t *allocated)
+{
+       if (*allocated < *i + 2) {
+               *allocated += 16;
+               keys = xrealloc(keys, *allocated, sizeof(k));
+       }
+       keys[*i] = k;
+       (*i)++;
+       keys[*i] = NULL;
+       return keys;
+}
+
+static int
+nss_convert_pubkey(Key *k)
+{
+       u_char *n;
+       unsigned int len;
+       char *p;
+
+       switch (k->type) {
+               case KEY_RSA:
+                       n = k->nss->pubk->u.rsa.modulus.data;
+                       len = k->nss->pubk->u.rsa.modulus.len;
+
+                       if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
+                               fatal("nss_convert_pubkey: BN_bin2bn failed");
+                       }
+
+                       n = k->nss->pubk->u.rsa.publicExponent.data;
+                       len = k->nss->pubk->u.rsa.publicExponent.len;
+
+                       if (BN_bin2bn(n, len, k->rsa->e) == NULL) {
+                               fatal("nss_convert_pubkey: BN_bin2bn failed");
+                       }
+                       break;
+               case KEY_DSA:
+                       n = k->nss->pubk->u.dsa.params.prime.data;
+                       len = k->nss->pubk->u.dsa.params.prime.len;
+
+                       if (BN_bin2bn(n, len, k->dsa->p) == NULL) {
+                               fatal("nss_convert_pubkey: BN_bin2bn failed");
+                       }
+
+                       n = k->nss->pubk->u.dsa.params.subPrime.data;
+                       len = k->nss->pubk->u.dsa.params.subPrime.len;
+
+                       if (BN_bin2bn(n, len, k->dsa->q) == NULL) {
+                               fatal("nss_convert_pubkey: BN_bin2bn failed");
+                       }
+
+                       n = k->nss->pubk->u.dsa.params.base.data;
+                       len = k->nss->pubk->u.dsa.params.base.len;
+
+                       if (BN_bin2bn(n, len, k->dsa->g) == NULL) {
+                               fatal("nss_convert_pubkey: BN_bin2bn failed");
+                       }
+
+                       n = k->nss->pubk->u.dsa.publicValue.data;
+                       len = k->nss->pubk->u.dsa.publicValue.len;
+
+                       if (BN_bin2bn(n, len, k->dsa->pub_key) == NULL) {
+                               fatal("nss_convert_pubkey: BN_bin2bn failed");
+                       }
+                       break;
+       }
+
+       p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+       debug("fingerprint %u %s", key_size(k), p);
+       xfree(p);
+
+       return 0;
+}
+
+static Key **
+nss_find_privkeys(const char *tokenname, const char *keyname,
+    char *password)
+{
+       Key *k = NULL;
+       Key **keys = NULL;
+       PK11SlotList *slots;
+       PK11SlotListElement *sle;
+       size_t allocated = 0;
+       size_t i = 0;
+
+       if ((slots=PK11_FindSlotsByNames(NULL, NULL, tokenname, PR_TRUE)) == 
NULL) {
+               if (tokenname == NULL) {
+                       debug("No NSS token found");
+               } else {
+                       debug("NSS token not found: %s", tokenname);
+               }
+               return NULL;
+       }
+       
+       for (sle = slots->head; sle; sle = sle->next) {
+               SECKEYPrivateKeyList *list;
+               SECKEYPrivateKeyListNode *node;
+               char *tmppass = password;
+                               
+               if (PK11_NeedLogin(sle->slot)) {
+                       if (password == NULL) {
+                               char *prompt;
+                               if (asprintf(&prompt, "Enter passphrase for 
token %s: ",
+                                       PK11_GetTokenName(sle->slot)) < 0)
+                                       fatal("password_cb: asprintf failed");
+                               tmppass = read_passphrase(prompt, 
RP_ALLOW_STDIN);
+                       }
+                       PK11_Authenticate(sle->slot, PR_TRUE, tmppass);
+               }
+
+               debug("Looking for: %s:%s", tokenname, keyname);
+               list = PK11_ListPrivKeysInSlot(sle->slot, (char *)keyname,
+                       tmppass);
+               if (list == NULL && keyname != NULL) {
+                       char *fooname;
+                       /* NSS bug workaround */
+                       if (asprintf(&fooname, "%s~", keyname) < 0) {
+                               error("nss_find_privkey: asprintf failed");
+                               PK11_FreeSlotList(slots);
+                               return NULL;
+                       }
+                       list = PK11_ListPrivKeysInSlot(sle->slot, fooname,
+                       tmppass);
+                       free(fooname);
+               }
+               if (list == NULL && keyname != NULL) {
+                       CERTCertificate *cert;
+                       SECKEYPrivateKey *privk;
+                       cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
+                               (char *)keyname);
+                       if (cert == NULL)
+                               goto cleanup;
+                       privk = PK11_FindPrivateKeyFromCert(sle->slot, cert, 
tmppass);
+                       CERT_DestroyCertificate(cert);
+                       if (privk == NULL)
+                               goto cleanup;
+                       if ((k=make_key_from_privkey(privk, tmppass)) != NULL) {
+                               nss_convert_pubkey(k);
+                               keys = add_key_to_list(k, keys, &i, &allocated);
+                       }
+                       SECKEY_DestroyPrivateKey(privk);
+               } else {
+                       if (list == NULL)
+                               goto cleanup;
+                       for (node=PRIVKEY_LIST_HEAD(list); 
!PRIVKEY_LIST_END(node, list);
+                               node=PRIVKEY_LIST_NEXT(node))
+                               if ((k=make_key_from_privkey(node->key, 
tmppass)) != NULL) {
+                                       nss_convert_pubkey(k);
+                                       keys = add_key_to_list(k, keys, &i, 
&allocated);
+                               }
+                       SECKEY_DestroyPrivateKeyList(list);
+               }
+cleanup:
+               if (password == NULL && tmppass != NULL) {
+                       memset(tmppass, 0, strlen(tmppass));
+                       xfree(tmppass);
+               }
+       }
+       PK11_FreeSlotList(slots);
+
+       return keys;
+}
+
+Key **
+nss_get_keys(const char *tokenname, const char *keyname,
+    char *password)
+{
+       Key **keys;
+
+       if (nss_init(NULL) == -1) {
+               error("Failed to initialize NSS library");
+               return NULL;
+       }
+
+       keys = nss_find_privkeys(tokenname, keyname, password);
+       if (keys == NULL && keyname != NULL) {
+               error("Cannot find key in nss, token removed");
+               return NULL;
+       }
+#if 0
+       keys = xcalloc(3, sizeof(Key *));
+
+       if (k->type == KEY_RSA) {
+               n = key_new_nss_copy(KEY_RSA1, k);
+
+               keys[0] = n;
+               keys[1] = k;
+               keys[2] = NULL;
+       } else {
+               keys[0] = k;
+               keys[1] = NULL;
+       }
+#endif
+       return keys;
+}
+
+char *
+nss_get_key_label(Key *key)
+{
+       char *label, *nickname;
+       
+       nickname = PK11_GetPrivateKeyNickname(key->nss->privk);
+       label = xstrdup(nickname);
+       PORT_Free(nickname);
+
+       return label;
+}
+
+#endif /* HAVE_LIBNSS */

Reply via email to