1523 lines
41 KiB
Diff
1523 lines
41 KiB
Diff
diff -up openssh-5.3p1/authfd.c.nss-keys openssh-5.3p1/authfd.c
|
|
--- openssh-5.3p1/authfd.c.nss-keys 2006-09-01 07:38:36.000000000 +0200
|
|
+++ openssh-5.3p1/authfd.c 2009-11-27 13:43:00.000000000 +0100
|
|
@@ -626,6 +626,45 @@ ssh_update_card(AuthenticationConnection
|
|
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.
|
|
diff -up openssh-5.3p1/authfd.h.nss-keys openssh-5.3p1/authfd.h
|
|
--- openssh-5.3p1/authfd.h.nss-keys 2006-08-05 04:39:39.000000000 +0200
|
|
+++ openssh-5.3p1/authfd.h 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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_remove_all_identities(Authentic
|
|
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],
|
|
diff -up openssh-5.3p1/configure.ac.nss-keys openssh-5.3p1/configure.ac
|
|
--- openssh-5.3p1/configure.ac.nss-keys 2009-11-27 13:42:57.000000000 +0100
|
|
+++ openssh-5.3p1/configure.ac 2009-11-27 13:48:44.000000000 +0100
|
|
@@ -3526,6 +3526,21 @@ AC_ARG_WITH(kerberos5,
|
|
]
|
|
)
|
|
|
|
+# 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/nss3 -I/usr/include/nspr4"
|
|
+ AC_CHECK_HEADERS(pk11pub.h)
|
|
+ LIBS="$LIBS -lnss3 -lplc4"
|
|
+ AC_CHECK_DECLS([SEC_ERROR_LOCKED_PASSWORD], [], [], [#include <secerr.h>])
|
|
+ fi
|
|
+ ])
|
|
+AC_SUBST(LIBNSS)
|
|
+
|
|
# Looking for programs, paths and files
|
|
|
|
PRIVSEP_PATH=/var/empty
|
|
@@ -4253,6 +4269,7 @@ echo " TCP Wrappers support
|
|
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 -up openssh-5.3p1/key.c.nss-keys openssh-5.3p1/key.c
|
|
--- openssh-5.3p1/key.c.nss-keys 2008-11-03 09:24:17.000000000 +0100
|
|
+++ openssh-5.3p1/key.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -96,6 +96,54 @@ key_new(int type)
|
|
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 @@ key_free(Key *k)
|
|
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 -up openssh-5.3p1/key.h.nss-keys openssh-5.3p1/key.h
|
|
--- openssh-5.3p1/key.h.nss-keys 2008-06-12 20:40:35.000000000 +0200
|
|
+++ openssh-5.3p1/key.h 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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 {
|
|
@@ -48,16 +54,30 @@ enum fp_rep {
|
|
|
|
/* 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 -up openssh-5.3p1/Makefile.in.nss-keys openssh-5.3p1/Makefile.in
|
|
--- openssh-5.3p1/Makefile.in.nss-keys 2009-08-28 02:47:38.000000000 +0200
|
|
+++ openssh-5.3p1/Makefile.in 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b
|
|
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 jpake.o schnorr.o
|
|
+ entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o nsskeys.o
|
|
|
|
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
|
|
sshconnect.o sshconnect1.o sshconnect2.o mux.o \
|
|
diff -up /dev/null openssh-5.3p1/nsskeys.c
|
|
--- /dev/null 2009-11-27 11:08:21.619709673 +0100
|
|
+++ openssh-5.3p1/nsskeys.c 2009-11-27 13:45:42.000000000 +0100
|
|
@@ -0,0 +1,443 @@
|
|
+/*
|
|
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
|
|
+ * Copyright (c) 2007 Red Hat, Inc. All rights reserved.
|
|
+ * Copyright (c) 2009 Pierre Ossman for Cendio AB
|
|
+ *
|
|
+ * 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 <secmod.h>
|
|
+#include <secerr.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) {
|
|
+ debug("Failed to initialize NSS library. Attempting without DB...");
|
|
+ if (NSS_NoDB_Init(NULL) != SECSuccess)
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (pwfn == NULL) {
|
|
+ pwfn = password_cb;
|
|
+ }
|
|
+
|
|
+ PK11_SetPasswordFunc(pwfn);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+nss_load_module(const char *modpath)
|
|
+{
|
|
+ char spec[MAXPATHLEN + 40];
|
|
+ SECMODModule *module;
|
|
+
|
|
+ debug("loading PKCS#11 module '%s'", modpath);
|
|
+
|
|
+ snprintf(spec, sizeof(spec), "library=\"%s\" name=\"Foobar\"", modpath);
|
|
+ module = SECMOD_LoadUserModule(spec, NULL, PR_FALSE);
|
|
+ if (!module || !module->loaded) {
|
|
+ if (module)
|
|
+ SECMOD_DestroyModule(module);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ 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 int
|
|
+nss_authenticate(PK11SlotInfo *slot, char *password, int pwprompts, char **output)
|
|
+{
|
|
+ int i, quit;
|
|
+
|
|
+ *output = NULL;
|
|
+
|
|
+ if (!PK11_NeedLogin(slot))
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < pwprompts; i++) {
|
|
+ SECStatus rv;
|
|
+ CK_TOKEN_INFO info;
|
|
+
|
|
+ rv = PK11_GetTokenInfo(slot, &info);
|
|
+ if (rv != SECSuccess) {
|
|
+ error("Failed to get information for token %s",
|
|
+ PK11_GetTokenName(slot));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (info.flags & CKF_USER_PIN_LOCKED) {
|
|
+ error("Passphrase for token %s is locked",
|
|
+ PK11_GetTokenName(slot));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (info.flags & CKF_USER_PIN_FINAL_TRY)
|
|
+ debug2("Final passphrase attempt for token %s",
|
|
+ PK11_GetTokenName(slot));
|
|
+ else if (info.flags & CKF_USER_PIN_COUNT_LOW)
|
|
+ debug2("Previous failed passphrase attempt for token %s",
|
|
+ PK11_GetTokenName(slot));
|
|
+
|
|
+ if (password != NULL)
|
|
+ *output = xstrdup(password);
|
|
+ else {
|
|
+ char *prompt;
|
|
+ if (asprintf(&prompt, "Enter passphrase for token %s: ",
|
|
+ PK11_GetTokenName(slot)) < 0)
|
|
+ fatal("password_cb: asprintf failed");
|
|
+ *output = read_passphrase(prompt, RP_ALLOW_STDIN);
|
|
+ }
|
|
+
|
|
+ if (strcmp(*output, "") == 0) {
|
|
+ debug2("no passphrase given, ignoring slot");
|
|
+ quit = 1;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ quit = 0;
|
|
+
|
|
+ rv = PK11_Authenticate(slot, PR_TRUE, *output);
|
|
+ if (rv == SECSuccess)
|
|
+ return 0;
|
|
+
|
|
+ switch (PORT_GetError()) {
|
|
+ case SEC_ERROR_BAD_PASSWORD:
|
|
+ debug2("Incorrect passphrase, try again...");
|
|
+ break;
|
|
+ case SEC_ERROR_INVALID_ARGS:
|
|
+ case SEC_ERROR_BAD_DATA:
|
|
+ debug2("Invalid passphrase, try again...");
|
|
+ break;
|
|
+#if HAVE_SEC_ERROR_LOCKED_PASSWORD
|
|
+ case SEC_ERROR_LOCKED_PASSWORD:
|
|
+ error("Unable to authenticate, token passphrase is locked");
|
|
+ quit = 1;
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ error("Failure while authenticating against token");
|
|
+ quit = 1;
|
|
+ }
|
|
+
|
|
+cleanup:
|
|
+ memset(*output, 0, strlen(*output));
|
|
+ xfree(*output);
|
|
+ *output = NULL;
|
|
+
|
|
+ /* No point in retrying the same password */
|
|
+ if (password != NULL)
|
|
+ break;
|
|
+
|
|
+ if (quit)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static Key **
|
|
+nss_find_privkeys(const char *tokenname, const char *keyname,
|
|
+ char *password, int pwprompts)
|
|
+{
|
|
+ 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;
|
|
+
|
|
+ if (nss_authenticate(sle->slot, password, pwprompts, &tmppass) == -1)
|
|
+ break;
|
|
+
|
|
+ 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 (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, int pwprompts, int num_modules, const char **modules)
|
|
+{
|
|
+ int i;
|
|
+ Key **keys;
|
|
+
|
|
+ if (nss_init(NULL) == -1) {
|
|
+ error("Failed to initialize NSS library");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (i = 0;i < num_modules;i++) {
|
|
+ if (nss_load_module(modules[i]) == -1) {
|
|
+ error("Failed to load PKCS#11 module '%s'", modules[i]);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ keys = nss_find_privkeys(tokenname, keyname, password, pwprompts);
|
|
+ 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 */
|
|
diff -up /dev/null openssh-5.3p1/nsskeys.h
|
|
--- /dev/null 2009-11-27 11:08:21.619709673 +0100
|
|
+++ openssh-5.3p1/nsskeys.h 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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 *, int , int , const char **);
|
|
+char *nss_get_key_label(Key *);
|
|
+/*void sc_close(void);*/
|
|
+/*int sc_put_key(Key *, const char *);*/
|
|
+
|
|
+#endif
|
|
+#endif
|
|
diff -up openssh-5.3p1/readconf.c.nss-keys openssh-5.3p1/readconf.c
|
|
--- openssh-5.3p1/readconf.c.nss-keys 2009-07-05 23:12:27.000000000 +0200
|
|
+++ openssh-5.3p1/readconf.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -124,6 +124,7 @@ typedef enum {
|
|
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
|
|
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
|
|
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
|
|
+ oUseNSS, oNSSToken, oNSSModule,
|
|
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
|
|
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
|
|
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
|
|
@@ -210,6 +211,15 @@ static struct {
|
|
#else
|
|
{ "smartcarddevice", oUnsupported },
|
|
#endif
|
|
+#ifdef HAVE_LIBNSS
|
|
+ { "usenss", oUseNSS },
|
|
+ { "nsstoken", oNSSToken },
|
|
+ { "nssmodule", oNSSModule },
|
|
+#else
|
|
+ { "usenss", oUnsupported },
|
|
+ { "nsstoken", oNSSToken },
|
|
+ { "nssmodule", oUnsupported },
|
|
+#endif
|
|
{ "clearallforwardings", oClearAllForwardings },
|
|
{ "enablesshkeysign", oEnableSSHKeysign },
|
|
{ "verifyhostkeydns", oVerifyHostKeyDNS },
|
|
@@ -613,6 +623,28 @@ parse_string:
|
|
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 oNSSModule:
|
|
+ arg = strdelim(&s);
|
|
+ if (!arg || *arg == '\0')
|
|
+ fatal("%.200s line %d: Missing argument.", filename, linenum);
|
|
+ if (*activep) {
|
|
+ intptr = &options->num_nss_modules;
|
|
+ if (*intptr >= SSH_MAX_NSS_MODULES)
|
|
+ fatal("%.200s line %d: Too many PKCS#11 modules specified (max %d).",
|
|
+ filename, linenum, SSH_MAX_NSS_MODULES);
|
|
+ charptr = &options->nss_modules[*intptr];
|
|
+ *charptr = xstrdup(arg);
|
|
+ *intptr = *intptr + 1;
|
|
+ }
|
|
+ break;
|
|
case oProxyCommand:
|
|
charptr = &options->proxy_command;
|
|
parse_command:
|
|
@@ -1052,6 +1084,9 @@ initialize_options(Options * options)
|
|
options->preferred_authentications = NULL;
|
|
options->bind_address = NULL;
|
|
options->smartcard_device = NULL;
|
|
+ options->use_nss = -1;
|
|
+ options->nss_token = NULL;
|
|
+ options->num_nss_modules = 0;
|
|
options->enable_ssh_keysign = - 1;
|
|
options->no_host_authentication_for_localhost = - 1;
|
|
options->identities_only = - 1;
|
|
@@ -1183,6 +1218,8 @@ fill_default_options(Options * options)
|
|
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 -up openssh-5.3p1/readconf.h.nss-keys openssh-5.3p1/readconf.h
|
|
--- openssh-5.3p1/readconf.h.nss-keys 2009-07-05 23:12:27.000000000 +0200
|
|
+++ openssh-5.3p1/readconf.h 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -85,6 +85,10 @@ typedef struct {
|
|
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 num_nss_modules; /* Number of PCKS#11 modules. */
|
|
+ char *nss_modules[SSH_MAX_NSS_MODULES];
|
|
int verify_host_key_dns; /* Verify host key using DNS */
|
|
|
|
int num_identity_files; /* Number of files for RSA/DSA identities. */
|
|
diff -up openssh-5.3p1/ssh-add.c.nss-keys openssh-5.3p1/ssh-add.c
|
|
--- openssh-5.3p1/ssh-add.c.nss-keys 2008-02-28 09:13:52.000000000 +0100
|
|
+++ openssh-5.3p1/ssh-add.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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"
|
|
@@ -307,6 +316,128 @@ do_file(AuthenticationConnection *ac, in
|
|
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)
|
|
{
|
|
@@ -334,6 +465,10 @@ main(int argc, char **argv)
|
|
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();
|
|
@@ -351,7 +486,7 @@ main(int argc, char **argv)
|
|
"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':
|
|
@@ -373,6 +508,11 @@ main(int argc, char **argv)
|
|
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;
|
|
@@ -387,6 +527,11 @@ main(int argc, char **argv)
|
|
goto done;
|
|
}
|
|
break;
|
|
+#ifdef HAVE_LIBNSS
|
|
+ case 'T':
|
|
+ token_id = optarg;
|
|
+ break;
|
|
+#endif
|
|
default:
|
|
usage();
|
|
ret = 1;
|
|
@@ -400,6 +545,40 @@ main(int argc, char **argv)
|
|
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 -up openssh-5.3p1/ssh-agent.c.nss-keys openssh-5.3p1/ssh-agent.c
|
|
--- openssh-5.3p1/ssh-agent.c.nss-keys 2009-06-21 09:50:15.000000000 +0200
|
|
+++ openssh-5.3p1/ssh-agent.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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 @@ send:
|
|
}
|
|
#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, 1, 0, NULL);
|
|
+ /* 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, 1, 0, NULL);
|
|
+ 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_message(SocketEntry *e)
|
|
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);
|
|
diff -up openssh-5.3p1/ssh.c.nss-keys openssh-5.3p1/ssh.c
|
|
--- openssh-5.3p1/ssh.c.nss-keys 2009-07-05 23:16:56.000000000 +0200
|
|
+++ openssh-5.3p1/ssh.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -105,6 +105,9 @@
|
|
#ifdef SMARTCARD
|
|
#include "scard.h"
|
|
#endif
|
|
+#ifdef HAVE_LIBNSS
|
|
+#include "nsskeys.h"
|
|
+#endif
|
|
|
|
extern char *__progname;
|
|
|
|
@@ -1234,9 +1237,11 @@ load_public_identity_files(void)
|
|
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) {
|
|
@@ -1259,6 +1264,29 @@ load_public_identity_files(void)
|
|
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,
|
|
+ options.number_of_password_prompts, options.num_nss_modules,
|
|
+ options.nss_modules)) != 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 -up openssh-5.3p1/ssh-dss.c.nss-keys openssh-5.3p1/ssh-dss.c
|
|
--- openssh-5.3p1/ssh-dss.c.nss-keys 2006-11-07 13:14:42.000000000 +0100
|
|
+++ openssh-5.3p1/ssh-dss.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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 @@ ssh_dss_sign(const Key *key, u_char **si
|
|
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 @@ ssh_dss_sign(const Key *key, u_char **si
|
|
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;
|
|
diff -up openssh-5.3p1/ssh.h.nss-keys openssh-5.3p1/ssh.h
|
|
--- openssh-5.3p1/ssh.h.nss-keys 2006-08-05 04:39:41.000000000 +0200
|
|
+++ openssh-5.3p1/ssh.h 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -28,6 +28,12 @@
|
|
#define SSH_MAX_IDENTITY_FILES 100
|
|
|
|
/*
|
|
+ * Maximum number of PKCS#11 modules that can be specified in configuration
|
|
+ * files or on the command line.
|
|
+ */
|
|
+#define SSH_MAX_NSS_MODULES 10
|
|
+
|
|
+/*
|
|
* Maximum length of lines in authorized_keys file.
|
|
* Current value permits 16kbit RSA and RSA1 keys and 8kbit DSA keys, with
|
|
* some room for options and comments.
|
|
diff -up openssh-5.3p1/ssh-keygen.c.nss-keys openssh-5.3p1/ssh-keygen.c
|
|
--- openssh-5.3p1/ssh-keygen.c.nss-keys 2009-06-22 08:11:07.000000000 +0200
|
|
+++ openssh-5.3p1/ssh-keygen.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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 @@ do_download(struct passwd *pw, const cha
|
|
}
|
|
#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, 1, 0, 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 @@ main(int argc, char **argv)
|
|
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 @@ main(int argc, char **argv)
|
|
}
|
|
|
|
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 @@ main(int argc, char **argv)
|
|
case 'g':
|
|
print_generic = 1;
|
|
break;
|
|
+ case 'n':
|
|
+ use_nss = 1;
|
|
+ download = 1;
|
|
+ break;
|
|
case 'P':
|
|
identity_passphrase = optarg;
|
|
break;
|
|
@@ -1187,10 +1217,10 @@ main(int argc, char **argv)
|
|
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 @@ main(int argc, char **argv)
|
|
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)
|
|
diff -up openssh-5.3p1/ssh-rsa.c.nss-keys openssh-5.3p1/ssh-rsa.c
|
|
--- openssh-5.3p1/ssh-rsa.c.nss-keys 2006-09-01 07:38:37.000000000 +0200
|
|
+++ openssh-5.3p1/ssh-rsa.c 2009-11-27 13:43:01.000000000 +0100
|
|
@@ -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 @@ ssh_rsa_sign(const Key *key, u_char **si
|
|
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 @@ ssh_rsa_sign(const Key *key, u_char **si
|
|
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 @@ ssh_rsa_sign(const Key *key, u_char **si
|
|
xfree(sig);
|
|
return -1;
|
|
}
|
|
+#ifdef HAVE_LIBNSS
|
|
+ }
|
|
+#endif
|
|
/* encode signature */
|
|
buffer_init(&b);
|
|
buffer_put_cstring(&b, "ssh-rsa");
|