[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#558309: please incorporate nss patches from Fedora



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-dev@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-ssh@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 <cjwatson@debian.org>, Matthew Vernon <matthew@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 <aba@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 to: