rpms/openssh/FC-6 openssh-4.3p2-cve-2007-3102.patch, NONE, 1.1 openssh-4.3p2-cve-2007-4752.patch, NONE, 1.1 openssh-4.3p2-nss-keys.patch, NONE, 1.1 openssh-4.3p2-selinux-rolechg.patch, 1.1, 1.2 openssh.spec, 1.101, 1.102

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Tue Oct 2 13:34:48 UTC 2007


Author: tmraz

Update of /cvs/dist/rpms/openssh/FC-6
In directory cvs.devel.redhat.com:/tmp/cvs-serv2292

Modified Files:
	openssh-4.3p2-selinux-rolechg.patch openssh.spec 
Added Files:
	openssh-4.3p2-cve-2007-3102.patch 
	openssh-4.3p2-cve-2007-4752.patch openssh-4.3p2-nss-keys.patch 
Log Message:
* Tue Oct  2 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-25
- do not fall back on trusted X11 cookies (CVE-2007-4752) (#280471)

* Fri Jul 13 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-24
- fixed audit log injection problem (CVE-2007-3102) (#248059)

* Thu Jun 21 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-23
- document where the nss certificate and token dbs are looked for

* Wed Jun 20 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-22
- experimental support for PKCS#11 tokens through libnss3 (#183423)

* Tue Apr 03 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-21
- correctly setup context when empty level requested (#234951)
- and always request default level as returned by getseuserbyname (#231695)


openssh-4.3p2-cve-2007-3102.patch:
 loginrec.c |   42 +++++++++++++++++++++++++++++++++++++++---
 1 files changed, 39 insertions(+), 3 deletions(-)

--- NEW FILE openssh-4.3p2-cve-2007-3102.patch ---
--- openssh-4.3p2/loginrec.c.inject-fix	2007-06-20 21:18:00.000000000 +0200
+++ openssh-4.3p2/loginrec.c	2007-07-13 15:25:35.000000000 +0200
@@ -1389,11 +1389,44 @@
 #endif /* USE_WTMPX */
 
 #ifdef HAVE_LINUX_AUDIT
+static void
+_audit_hexscape(const char *what, char *where, unsigned int size)
+{
+	const char *ptr = what;
+	const char *hex = "0123456789ABCDEF";
+
+	while (*ptr) {
+		if (*ptr == '"' || *ptr < 0x21 || *ptr > 0x7E) {
+			unsigned int i;
+			ptr = what;
+			for (i = 0; *ptr && i+2 < size; i += 2) {
+				where[i] = hex[((unsigned)*ptr & 0xF0)>>4]; /* Upper nibble */
+				where[i+1] = hex[(unsigned)*ptr & 0x0F];   /* Lower nibble */
+				ptr++;
+			}
+			where[i] = '\0';
+			return;
+		}
+		ptr++;
+	}
+	where[0] = '"';
+	if ((unsigned)(ptr - what) < size - 3)
+	{
+		size = ptr - what + 3;
+	}
+	strncpy(where + 1, what, size - 3);
+	where[size-2] = '"';
+	where[size-1] = '\0';
+}
+
+#define AUDIT_LOG_SIZE 128
+#define AUDIT_ACCT_SIZE (AUDIT_LOG_SIZE - 8)
+
 int
 linux_audit_record_event(int uid, const char *username,
 	const char *hostname, const char *ip, const char *ttyn, int success)
 {
-	char buf[64];
+	char buf[AUDIT_LOG_SIZE];
 	int audit_fd, rc;
 
 	audit_fd = audit_open();
@@ -1406,8 +1439,11 @@
 	}
 	if (username == NULL)
 		snprintf(buf, sizeof(buf), "uid=%d", uid);
-	else
-		snprintf(buf, sizeof(buf), "acct=%s", username);
+	else {
+		char encoded[AUDIT_ACCT_SIZE];
+		_audit_hexscape(username, encoded, sizeof(encoded));
+		snprintf(buf, sizeof(buf), "acct=%s", encoded);
+	}
 	rc = audit_log_user_message(audit_fd, AUDIT_USER_LOGIN,
 		buf, hostname, ip, ttyn, success);
 	close(audit_fd);

openssh-4.3p2-cve-2007-4752.patch:
 clientloop.c |   36 +++++++++++++++++++++++-------------
 1 files changed, 23 insertions(+), 13 deletions(-)

--- NEW FILE openssh-4.3p2-cve-2007-4752.patch ---
Do not fall back on trusted X11 cookies when untrusted cookie generation
fails.
--- ssh/clientloop.c	2007/08/07 07:32:53	1.180
+++ ssh/clientloop.c	2007/08/15 08:14:46	1.181
@@ -282,19 +282,29 @@
 					generated = 1;
 			}
 		}
-		snprintf(cmd, sizeof(cmd),
-		    "%s %s%s list %s 2>" _PATH_DEVNULL,
-		    xauth_path,
-		    generated ? "-f " : "" ,
-		    generated ? xauthfile : "",
-		    display);
-		debug2("x11_get_proto: %s", cmd);
-		f = popen(cmd, "r");
-		if (f && fgets(line, sizeof(line), f) &&
-		    sscanf(line, "%*s %511s %511s", proto, data) == 2)
-			got_data = 1;
-		if (f)
-			pclose(f);
+
+		/*
+		 * When in untrusted mode, we read the cookie only if it was
+		 * successfully generated as an untrusted one in the step
+		 * above.
+		 */
+		if (trusted || generated) {
+			snprintf(cmd, sizeof(cmd),
+			    "%s %s%s list %s 2>" _PATH_DEVNULL,
+			    xauth_path,
+			    generated ? "-f " : "" ,
+			    generated ? xauthfile : "",
+			    display);
+			debug2("x11_get_proto: %s", cmd);
+			f = popen(cmd, "r");
+			if (f && fgets(line, sizeof(line), f) &&
+			    sscanf(line, "%*s %511s %511s", proto, data) == 2)
+				got_data = 1;
+			if (f)
+				pclose(f);
+		} else
+			error("Warning: untrusted X11 forwarding setup failed: "
+			    "xauth key data not generated");
 	}
 
 	if (do_unlink) {

openssh-4.3p2-nss-keys.patch:
 Makefile.in  |    4 
 README.nss   |   38 ++++++
 authfd.c     |   39 +++++++
 authfd.h     |    8 +
 configure.ac |   16 ++
 key.c        |   62 +++++++++++
 key.h        |   20 +++
 nsskeys.c    |  327 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 nsskeys.h    |   39 +++++++
 readconf.c   |   20 +++
 readconf.h   |    2 
 ssh-add.c    |  168 ++++++++++++++++++++++++++++++
 ssh-agent.c  |  121 +++++++++++++++++++++
 ssh-dss.c    |   36 ++++++
 ssh-keygen.c |   50 ++++++++-
 ssh-rsa.c    |   42 +++++++
 ssh.c        |   28 +++++
 17 files changed, 1009 insertions(+), 11 deletions(-)

--- NEW FILE openssh-4.3p2-nss-keys.patch ---
--- openssh-4.3p2/ssh-rsa.c.nss-keys	2005-06-17 04:59:35.000000000 +0200
+++ openssh-4.3p2/ssh-rsa.c	2007-06-20 20:09:35.000000000 +0200
@@ -27,6 +27,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 */
@@ -45,6 +49,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);
@@ -54,9 +90,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));
 
@@ -77,6 +110,9 @@
 		xfree(sig);
 		return -1;
 	}
+#ifdef HAVE_LIBNSS
+	}
+#endif
 	/* encode signature */
 	buffer_init(&b);
 	buffer_put_cstring(&b, "ssh-rsa");
--- /dev/null	2007-06-20 14:56:05.942081985 +0200
+++ openssh-4.3p2/README.nss	2007-06-20 20:09:35.000000000 +0200
@@ -0,0 +1,38 @@
+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'
+
+Tomas Mraz, Red Hat, Inc.
--- openssh-4.3p2/Makefile.in.nss-keys	2007-04-03 11:01:04.000000000 +0200
+++ openssh-4.3p2/Makefile.in	2007-06-20 20:09:35.000000000 +0200
@@ -42,7 +42,7 @@
 LD=@LD@
 CFLAGS=@CFLAGS@
 CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
-LIBS=@LIBS@
+LIBS=@LIBS@ @LIBNSS@
 LIBSELINUX=@LIBSELINUX@
 LIBAUDIT=@LIBAUDIT@
 LIBEDIT=@LIBEDIT@
@@ -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
+	entropy.o scard-opensc.o gss-genr.o nsskeys.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
 	sshconnect.o sshconnect1.o sshconnect2.o
--- openssh-4.3p2/ssh.c.nss-keys	2005-12-31 06:33:37.000000000 +0100
+++ openssh-4.3p2/ssh.c	2007-06-20 20:19:28.000000000 +0200
@@ -76,6 +76,9 @@
 #ifdef SMARTCARD
 #include "scard.h"
 #endif
+#ifdef HAVE_LIBNSS
+#include "nsskeys.h"
+#endif
 
 extern char *__progname;
 
@@ -1179,6 +1182,10 @@
 	char *filename;
 	int i = 0;
 	Key *public;
+#if defined(SMARTCARD) || defined(HAVE_LIBNSS)
+	Key **keys;
+#endif
+
 #ifdef SMARTCARD
 	Key **keys;
 
@@ -1202,6 +1209,26 @@
 		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 */
 	for (; i < options.num_identity_files; i++) {
 		filename = tilde_expand_filename(options.identity_files[i],
 		    original_real_uid);
@@ -1212,6 +1239,7 @@
 		options.identity_files[i] = filename;
 		options.identity_keys[i] = public;
 	}
+	debug("loaded %d keys", options.num_identity_files);
 }
 
 static void
--- openssh-4.3p2/ssh-agent.c.nss-keys	2005-11-05 05:15:00.000000000 +0100
+++ openssh-4.3p2/ssh-agent.c	2007-06-20 20:09:35.000000000 +0200
@@ -56,6 +56,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
@@ -667,6 +671,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
@@ -762,6 +874,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);
--- openssh-4.3p2/readconf.c.nss-keys	2005-12-13 09:33:20.000000000 +0100
+++ openssh-4.3p2/readconf.c	2007-06-20 20:09:35.000000000 +0200
@@ -106,6 +106,7 @@
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
+	oUseNSS, oNSSToken,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@@ -190,6 +191,13 @@
 #else
 	{ "smartcarddevice", oUnsupported },
 #endif
+#ifdef HAVE_LIBNSS
+	{ "usenss", oUseNSS },
+	{ "nsstoken", oNSSToken },
+#else
+	{ "usenss", oUnsupported },
+	{ "nsstoken", oNSSToken },
+#endif
 	{ "clearallforwardings", oClearAllForwardings },
 	{ "enablesshkeysign", oEnableSSHKeysign },
 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
@@ -562,6 +570,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:
@@ -1009,6 +1025,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;
@@ -1135,6 +1153,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)
--- openssh-4.3p2/configure.ac.nss-keys	2007-04-03 11:01:04.000000000 +0200
+++ openssh-4.3p2/configure.ac	2007-06-20 20:09:35.000000000 +0200
@@ -2989,6 +2989,21 @@
 	])
 AC_SUBST(LIBAUDIT)
 
+# Check whether user wants NSS support
+LIBNSS_MSG="no"
+LIBNSS=""
+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/nss3 -I/usr/include/nspr4"
+		AC_CHECK_HEADERS(pk11pub.h)
+		LIBNSS="-lnss3"
+	fi
+	])
+AC_SUBST(LIBNSS)
+
 # Check whether user wants Kerberos 5 support
 KRB5_MSG="no"
 AC_ARG_WITH(kerberos5,
@@ -3817,6 +3832,7 @@
 echo "                 KerberosV support: $KRB5_MSG"
 echo "                   SELinux support: $SELINUX_MSG"
 echo "               Linux audit support: $LINUX_AUDIT_MSG"
+echo "                       NSS support: $LIBNSS_MSG"
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
 echo "              TCP Wrappers support: $TCPW_MSG"
--- openssh-4.3p2/key.h.nss-keys	2003-11-17 11:18:23.000000000 +0100
+++ openssh-4.3p2/key.h	2007-06-20 20:09:35.000000000 +0200
@@ -29,11 +29,17 @@
 #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_NSS,
 	KEY_UNSPEC
 };
 enum fp_type {
@@ -47,16 +53,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 *);
--- openssh-4.3p2/ssh-add.c.nss-keys	2005-11-22 09:37:09.000000000 +0100
+++ openssh-4.3p2/ssh-add.c	2007-06-20 20:15:26.000000000 +0200
@@ -39,11 +39,19 @@
 
 #include <openssl/evp.h>
 
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include <secmod.h>
+#include <pk11pub.h>
+#include <keyhi.h>
+#include <cert.h>
+#endif
 #include "ssh.h"
 #include "rsa.h"
 #include "log.h"
 #include "xmalloc.h"
 #include "key.h"
+#include "nsskeys.h"
 #include "authfd.h"
 #include "authfile.h"
 #include "pathnames.h"
@@ -284,6 +292,117 @@
 	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;
+	
+	int count = 0;
+	
+	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 (ssh_update_nss_key(ac, add, tokenname, keyname,
+			passcache?passcache:"",	lifetime, confirm)) {
+			fprintf(stderr, "Key %s: %s:%s\n",
+				add?"added":"removed", tokenname, keyname);
+			count++;
+		} else {
+			fprintf(stderr, "Could not %s key: %s:%s\n",
+				add?"add":"remove", tokenname, keyname);
+		}
+		
+		PORT_Free(keyname);
+		count++;
+	}
+
+	if (passcache != NULL) {
+		memset(passcache, 0, strlen(passcache));
+		xfree(passcache);
+	}
+	
+	SECKEY_DestroyPrivateKeyList(list);
+	
+	return count;
+}
+#endif
+
 static void
 usage(void)
 {
@@ -311,6 +430,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();
@@ -328,7 +451,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':
@@ -352,7 +475,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;
@@ -367,6 +494,11 @@
 				goto done;
 			}
 			break;
+#ifdef HAVE_LIBNSS
+		case 'T':
+			token_id = optarg;
+			break;
+#endif
 		default:
 			usage();
 			ret = 1;
@@ -380,6 +512,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;
--- openssh-4.3p2/readconf.h.nss-keys	2005-12-13 09:29:02.000000000 +0100
+++ openssh-4.3p2/readconf.h	2007-06-20 20:09:35.000000000 +0200
@@ -85,6 +85,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. */
--- /dev/null	2007-06-20 14:56:05.942081985 +0200
+++ openssh-4.3p2/nsskeys.h	2007-06-20 20:09:35.000000000 +0200
@@ -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
--- openssh-4.3p2/authfd.h.nss-keys	2003-11-21 13:48:55.000000000 +0100
+++ openssh-4.3p2/authfd.h	2007-06-20 20:09:35.000000000 +0200
@@ -51,6 +51,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
 
@@ -85,6 +91,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],
--- openssh-4.3p2/authfd.c.nss-keys	2005-06-17 04:59:35.000000000 +0200
+++ openssh-4.3p2/authfd.c	2007-06-20 20:09:35.000000000 +0200
@@ -617,6 +617,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.
--- openssh-4.3p2/ssh-dss.c.nss-keys	2003-11-17 11:18:23.000000000 +0100
+++ openssh-4.3p2/ssh-dss.c	2007-06-20 20:09:35.000000000 +0200
@@ -35,6 +35,10 @@
 #include "log.h"
 #include "key.h"
 
+#ifdef HAVE_LIBNSS
+#include <cryptohi.h>
+#endif
+
 #define INTBLOB_LEN	20
 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
 
@@ -53,6 +57,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);
@@ -76,7 +108,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;
--- openssh-4.3p2/key.c.nss-keys	2005-06-17 04:59:35.000000000 +0200
+++ openssh-4.3p2/key.c	2007-06-20 20:09:35.000000000 +0200
@@ -88,6 +88,55 @@
 	return k;
 }
 
+#ifdef HAVE_LIBNSS
+Key *
+key_new_nss(int type)
+{
+	Key *k = key_new(type);
+
+	k->nss = xmalloc(sizeof(*k->nss));
+	memset(k->nss, 0, 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)
 {
@@ -141,6 +190,19 @@
 		fatal("key_free: bad key type %d", k->type);
 		break;
 	}
+#ifdef HAVE_LIBNSS
+	if (k->flags & KEY_FLAG_NSS) {
+		if (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);
 }
 
--- /dev/null	2007-06-20 14:56:05.942081985 +0200
+++ openssh-4.3p2/nsskeys.c	2007-06-20 20:09:35.000000000 +0200
@@ -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 */
--- openssh-4.3p2/ssh-keygen.c.nss-keys	2005-11-29 03:10:25.000000000 +0100
+++ openssh-4.3p2/ssh-keygen.c	2007-06-20 20:22:11.000000000 +0200
@@ -35,6 +35,11 @@
 #endif
 #include "dns.h"
 
+#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
@@ -456,6 +461,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)
 {
@@ -1009,7 +1034,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;
 	int log_level = SYSLOG_LEVEL_INFO;
@@ -1043,7 +1069,7 @@
 	}
 
 	while ((opt = getopt(ac, av,
-	    "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 = strtonum(optarg, 768, 32768, &errstr);
@@ -1083,6 +1109,10 @@
 		case 'g':
 			print_generic = 1;
 			break;
+		case 'n':
+			use_nss = 1;
+			download = 1;
+			break;
 		case 'P':
 			identity_passphrase = optarg;
 			break;
@@ -1114,9 +1144,10 @@
 		case 't':
 			key_type_name = optarg;
 			break;
-		case 'D':
-			download = 1;
 		case 'U':
+			download = 0;
+			/*FALLTHROUGH*/
+		case 'D':
 			reader_id = optarg;
 			break;
 		case 'v':
@@ -1200,6 +1231,17 @@
 	if (rr_hostname != NULL) {
 		do_print_resource_record(pw, rr_hostname);
 	}
+
+	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)

openssh-4.3p2-selinux-rolechg.patch:
 selinux.c |  168 +++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 129 insertions(+), 39 deletions(-)

Index: openssh-4.3p2-selinux-rolechg.patch
===================================================================
RCS file: /cvs/dist/rpms/openssh/FC-6/openssh-4.3p2-selinux-rolechg.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- openssh-4.3p2-selinux-rolechg.patch	1 Mar 2007 12:09:39 -0000	1.1
+++ openssh-4.3p2-selinux-rolechg.patch	2 Oct 2007 13:34:45 -0000	1.2
@@ -1,6 +1,34 @@
---- openssh-4.3p2/selinux.c.rolechg	2007-02-27 20:56:16.000000000 +0100
-+++ openssh-4.3p2/selinux.c	2007-02-27 21:42:09.000000000 +0100
-@@ -82,16 +82,80 @@
+--- openssh-4.3p2/selinux.c.rolechg	2007-04-03 11:01:05.000000000 +0200
++++ openssh-4.3p2/selinux.c	2007-04-03 16:09:49.000000000 +0200
+@@ -41,15 +41,15 @@
+ 	}
+ 	if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) {
+ 		error("Error translating default context.");
+-		goto out;
++		default_raw = NULL;
+ 	}
+ 	if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) {
+ 		error("Error translating selected context.");
+-		goto out;
++		selected_raw = NULL;
+ 	}
+ 	if (asprintf(&msg, "sshd: default-context=%s selected-context=%s",
+-		     default_context ? default_raw : "?",
+-		     selected_context ? selected_raw : "?") < 0) {
++		     default_raw ? default_raw : (default_context ? default_context : "?"),
++		     selected_raw ? selected_raw : (selected_context ? selected_context : "?")) < 0) {
+ 		error("Error allocating memory.");
+ 		goto out;
+ 	}
+@@ -74,6 +74,7 @@
+ 	int retval;
+ 	unsigned int bit = CONTEXT__CONTAINS;
+ 
++	debug("mls_range_allowed: src:%s dst:%s", src, dst);
+ 	retval = security_compute_av(src, dst, SECCLASS_CONTEXT, bit, &avd);
+ 	if (retval || ((bit & avd.allowed) != bit))
+ 		return 0;
+@@ -82,16 +83,81 @@
  }
  
  static int get_user_context(const char *user, const char *role, const char *level,
@@ -10,7 +38,8 @@
 -	else
 -		return get_default_context_with_level(user, level, NULL, context);
 +			    security_context_t *context) {
-+	if (get_default_context_with_level(user, level, NULL, context) != 0) {
++	if (level == NULL || level[0] == '\0' ||
++	    get_default_context_with_level(user, level, NULL, context) != 0) {
 +	        /* User may have requested a level completely outside of his 
 +	           allowed range. We get a context just for auditing as the
 +	           range check below will certainly fail for default context. */
@@ -89,7 +118,7 @@
  	char *seuser=NULL;
  	char *role=NULL;
  	int ret=-1;
-@@ -99,6 +163,8 @@
+@@ -99,6 +165,8 @@
  	const char *rlevel=NULL;
  	context_t con=NULL;
  
@@ -98,7 +127,7 @@
  	if (the_authctxt) {
  		if (the_authctxt->role != NULL) {
  			char *slash;
-@@ -113,7 +179,7 @@
+@@ -113,7 +181,7 @@
  	ret = getseuserbyname(name, &seuser, &dlevel);
  	
  	if (ret >= 0) {
@@ -107,7 +136,7 @@
  	}
  	
  	if (ret >= 0) {
-@@ -121,42 +187,38 @@
+@@ -121,42 +189,45 @@
  		if (inetd_flag && !rexeced_flag) {
  			security_context_t sshd_context=NULL;
  
@@ -135,8 +164,13 @@
 -				if (mls_range_allowed(default_context, user_context)) {
 -					send_audit_message(1, default_context, user_context);
 +			if (ret >= 0 && rlevel != NULL && rlevel[0]) {
++				security_context_t default_level_context = *default_context;
++				if (role != NULL && role[0]) {
++					if (get_user_context(seuser, role, dlevel, &default_level_context) < 0)
++						default_level_context = *default_context;
++				}
 +				/* verify that the requested range is contained in the user range */
-+				if (mls_range_allowed(*default_context, *user_context)) {
++				if (mls_range_allowed(default_level_context, *user_context)) {
  					logit("permit MLS level %s (user range %s)", rlevel, dlevel);
  				} else {
 -					send_audit_message(0, default_context, user_context);
@@ -147,6 +181,8 @@
 +					ret = -1;
 +					error("deny MLS level %s (user range %s)", rlevel, dlevel);
  				}
++				if (default_level_context != *default_context)
++					freecon(default_level_context);
  			}
 -			freecon(default_context);
  		} else {
@@ -164,7 +200,7 @@
  	}
  	
  	if (con)
-@@ -164,7 +226,7 @@
+@@ -164,7 +235,7 @@
  	free(role);
  	free(seuser);
  	free(dlevel);
@@ -173,7 +209,7 @@
  }
  
  void setup_selinux_pty(const char *name, const char *tty) {
-@@ -201,18 +263,37 @@
+@@ -201,18 +272,37 @@
  }
  
  void setup_selinux_exec_context(char *name) {


Index: openssh.spec
===================================================================
RCS file: /cvs/dist/rpms/openssh/FC-6/openssh.spec,v
retrieving revision 1.101
retrieving revision 1.102
diff -u -r1.101 -r1.102
--- openssh.spec	30 Mar 2007 20:02:49 -0000	1.101
+++ openssh.spec	2 Oct 2007 13:34:45 -0000	1.102
@@ -28,6 +28,9 @@
 # Do we want kerberos5 support (1=yes 0=no)
 %define kerberos5 1
 
+# Do we want NSS tokens support
+%define nss 1
+
 # Whether or not /sbin/nologin exists.
 %define nologin 1
 
@@ -61,7 +64,7 @@
 Summary: The OpenSSH implementation of SSH protocol versions 1 and 2
 Name: openssh
 Version: 4.3p2
-Release: 19%{?dist}%{?rescue_rel}
+Release: 24%{?dist}%{?rescue_rel}
 URL: http://www.openssh.com/portable.html
 #Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
 #Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.sig
@@ -105,6 +108,9 @@
 Patch51: openssh-4.3p2-mls.patch
 Patch52: openssh-4.3p2-selinux-rolechg.patch
 Patch53: openssh-4.3p2-cve-2006-5052.patch
+Patch54: openssh-4.3p2-nss-keys.patch
+Patch55: openssh-4.3p2-cve-2007-3102.patch
+Patch56: openssh-4.3p2-cve-2007-4752.patch
 License: BSD
 Group: Applications/Internet
 BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
@@ -135,6 +141,10 @@
 BuildRequires: krb5-devel
 %endif
 
+%if %{nss}
+BuildRequires: nss-devel
+%endif
+
 %if %{WITH_SELINUX}
 Requires: libselinux >= 1.27.7
 BuildRequires: libselinux-devel >= 1.27.7
@@ -247,6 +257,9 @@
 %patch51 -p1 -b .mls
 %patch52 -p1 -b .rolechg
 %patch53 -p1 -b .cve-2006-5052
+%patch54 -p1 -b .nss-keys
+%patch55 -p1 -b .inject-fix
+%patch56 -p1 -b .untrusted-only
 
 autoreconf
 
@@ -289,6 +302,9 @@
 	--enable-vendor-patchlevel="FC-%{version}-%{release}" \
 	--disable-strip \
 	--without-zlib-version-check \
+%if %{nss}
+	--with-nss \
+%endif
 %if %{scard}
 	--with-smartcard \
 %endif
@@ -372,6 +388,10 @@
 
 perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/*
 
+rm -f README.nss.nss-keys
+%if ! %{nss}
+rm -f README.nss
+%endif
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -491,6 +511,22 @@
 %endif
 
 %changelog
+* Tue Oct  2 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-25
+- do not fall back on trusted X11 cookies (CVE-2007-4752) (#280471)
+
+* Fri Jul 13 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-24
+- fixed audit log injection problem (CVE-2007-3102) (#248059)
+
+* Thu Jun 21 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-23
+- document where the nss certificate and token dbs are looked for
+
+* Wed Jun 20 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-22
+- experimental support for PKCS#11 tokens through libnss3 (#183423)
+
+* Tue Apr 03 2007 Tomas Mraz <tmraz at redhat.com> - 4.3p2-21
+- correctly setup context when empty level requested (#234951)
+- and always request default level as returned by getseuserbyname (#231695)
+
 * Fri Mar 30 2007 Miloslav Trmac <mitr at redhat.com> - 4.3p2-19
 - Fix an information leak in Kerberos password authentication (CVE-2006-5052)
   Resolves: #234640




More information about the fedora-cvs-commits mailing list