From c3274ccb320adeea4312dee08999db81cb3841fd Mon Sep 17 00:00:00 2001 From: Tomáš Mráz Date: Jun 20 2007 17:47:18 +0000 Subject: - experimental NSS keys support - correctly setup context when empty level requested (#234951) --- diff --git a/openssh-4.5p1-mls.patch b/openssh-4.5p1-mls.patch index d40f953..b8d7752 100644 --- a/openssh-4.5p1-mls.patch +++ b/openssh-4.5p1-mls.patch @@ -49,15 +49,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_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) { + error("Error allocating memory."); + goto out; + } @@ -95,7 +95,7 @@ +get_user_context(const char *sename, const char *role, const char *lvl, + security_context_t *sc) { +#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ if (get_default_context_with_level(sename, lvl, NULL, sc) != 0) { ++ if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 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. */ diff --git a/openssh-4.5p1-nss-keys.patch b/openssh-4.5p1-nss-keys.patch new file mode 100644 index 0000000..27b4afb --- /dev/null +++ b/openssh-4.5p1-nss-keys.patch @@ -0,0 +1,1416 @@ +diff -urpN openssh-4.5p1/authfd.c openssh-4.5p1.nss/authfd.c +--- openssh-4.5p1/authfd.c 2006-09-01 07:38:36.000000000 +0200 ++++ openssh-4.5p1.nss/authfd.c 2007-05-23 15:01:55.000000000 +0200 +@@ -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 -urpN openssh-4.5p1/authfd.h openssh-4.5p1.nss/authfd.h +--- openssh-4.5p1/authfd.h 2006-08-05 04:39:39.000000000 +0200 ++++ openssh-4.5p1.nss/authfd.h 2007-05-17 11:47:39.000000000 +0200 +@@ -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 -urpN openssh-4.5p1/configure.ac openssh-4.5p1.nss/configure.ac +--- openssh-4.5p1/configure.ac 2007-05-15 16:28:07.000000000 +0200 ++++ openssh-4.5p1.nss/configure.ac 2007-05-15 16:38:56.000000000 +0200 +@@ -3175,6 +3175,21 @@ AC_ARG_WITH(linux-audit, + ]) + 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(nss.h) ++ LIBNSS="-lnss3" ++ fi ++ ]) ++AC_SUBST(LIBNSS) ++ + # Check whether user wants Kerberos 5 support + KRB5_MSG="no" + AC_ARG_WITH(kerberos5, +@@ -3997,6 +4012,7 @@ echo " OSF SIA support + 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" +diff -urpN openssh-4.5p1/key.c openssh-4.5p1.nss/key.c +--- openssh-4.5p1/key.c 2006-11-07 13:14:42.000000000 +0100 ++++ openssh-4.5p1.nss/key.c 2007-06-20 14:30:11.000000000 +0200 +@@ -93,6 +93,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) + { +@@ -148,6 +196,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->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 -urpN openssh-4.5p1/key.h openssh-4.5p1.nss/key.h +--- openssh-4.5p1/key.h 2006-08-05 04:39:40.000000000 +0200 ++++ openssh-4.5p1.nss/key.h 2007-05-29 11:19:03.000000000 +0200 +@@ -29,11 +29,17 @@ + #include + #include + ++#ifdef HAVE_LIBNSS ++#include ++#include ++#endif ++ + typedef struct Key Key; + enum types { + KEY_RSA1, + KEY_RSA, + KEY_DSA, ++ KEY_NSS, + KEY_UNSPEC + }; + enum fp_type { +@@ -47,16 +53,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 -urpN openssh-4.5p1/Makefile.in openssh-4.5p1.nss/Makefile.in +--- openssh-4.5p1/Makefile.in 2007-05-15 16:28:07.000000000 +0200 ++++ openssh-4.5p1.nss/Makefile.in 2007-05-23 14:05:18.000000000 +0200 +@@ -43,7 +43,7 @@ CC=@CC@ + LD=@LD@ + CFLAGS=@CFLAGS@ + CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ +-LIBS=@LIBS@ ++LIBS=@LIBS@ @LIBNSS@ + LIBSELINUX=@LIBSELINUX@ + LIBAUDIT=@LIBAUDIT@ + SSHDLIBS=@SSHDLIBS@ +@@ -75,7 +75,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 ++ 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 +diff -urpN openssh-4.5p1/nsskeys.c openssh-4.5p1.nss/nsskeys.c +--- openssh-4.5p1/nsskeys.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-4.5p1.nss/nsskeys.c 2007-06-20 17:57:11.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 ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 */ +diff -urpN openssh-4.5p1/nsskeys.h openssh-4.5p1.nss/nsskeys.h +--- openssh-4.5p1/nsskeys.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-4.5p1.nss/nsskeys.h 2007-05-29 11:40:18.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 ++#include ++ ++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 +diff -urpN openssh-4.5p1/readconf.c openssh-4.5p1.nss/readconf.c +--- openssh-4.5p1/readconf.c 2006-09-01 07:38:37.000000000 +0200 ++++ openssh-4.5p1.nss/readconf.c 2007-06-20 17:51:38.000000000 +0200 +@@ -124,6 +124,7 @@ typedef enum { + oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, + oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, + oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, ++ oUseNSS, oNSSToken, + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, + oAddressFamily, oGssAuthentication, oGssDelegateCreds, +@@ -209,6 +210,13 @@ static struct { + #else + { "smartcarddevice", oUnsupported }, + #endif ++#ifdef HAVE_LIBNSS ++ { "usenss", oUseNSS }, ++ { "nsstoken", oNSSToken }, ++#else ++ { "usenss", oUnsupported }, ++ { "nsstoken", oNSSToken }, ++#endif + { "clearallforwardings", oClearAllForwardings }, + { "enablesshkeysign", oEnableSSHKeysign }, + { "verifyhostkeydns", oVerifyHostKeyDNS }, +@@ -601,6 +609,14 @@ 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 oProxyCommand: + charptr = &options->proxy_command; + parse_command: +@@ -1049,6 +1065,8 @@ 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->enable_ssh_keysign = - 1; + options->no_host_authentication_for_localhost = - 1; + options->identities_only = - 1; +@@ -1177,6 +1195,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 -urpN openssh-4.5p1/readconf.h openssh-4.5p1.nss/readconf.h +--- openssh-4.5p1/readconf.h 2006-08-05 04:39:40.000000000 +0200 ++++ openssh-4.5p1.nss/readconf.h 2007-06-18 10:41:58.000000000 +0200 +@@ -84,6 +84,8 @@ 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 verify_host_key_dns; /* Verify host key using DNS */ + + int num_identity_files; /* Number of files for RSA/DSA identities. */ +diff -urpN openssh-4.5p1/README.nss openssh-4.5p1.nss/README.nss +--- openssh-4.5p1/README.nss 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-4.5p1.nss/README.nss 2007-06-20 18:28:28.000000000 +0200 +@@ -0,0 +1,36 @@ ++How to use NSS tokens with OpenSSH? ++ ++This version of OpenSSH contains experimental support for authentication using ++keys stored in tokens stored in NSS database. This for example includes any ++PKCS#11 tokens which are installed in your NSS database. ++ ++As the code is experimental and preliminary only SSH protocol 2 is supported. ++ ++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. +diff -urpN openssh-4.5p1/ssh-add.c openssh-4.5p1.nss/ssh-add.c +--- openssh-4.5p1/ssh-add.c 2006-09-01 07:38:37.000000000 +0200 ++++ openssh-4.5p1.nss/ssh-add.c 2007-05-29 18:26:08.000000000 +0200 +@@ -43,6 +43,14 @@ + + #include + ++#ifdef HAVE_LIBNSS ++#include ++#include ++#include ++#include ++#include ++#endif ++ + #include + #include + #include +@@ -56,6 +64,7 @@ + #include "rsa.h" + #include "log.h" + #include "key.h" ++#include "nsskeys.h" + #include "buffer.h" + #include "authfd.h" + #include "authfile.h" +@@ -306,6 +315,117 @@ 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; ++ ++ 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) + { +@@ -333,6 +453,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(); +@@ -350,7 +474,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': +@@ -372,6 +496,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; +@@ -386,6 +515,11 @@ main(int argc, char **argv) + goto done; + } + break; ++#ifdef HAVE_LIBNSS ++ case 'T': ++ token_id = optarg; ++ break; ++#endif + default: + usage(); + ret = 1; +@@ -399,6 +533,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 -urpN openssh-4.5p1/ssh-agent.c openssh-4.5p1.nss/ssh-agent.c +--- openssh-4.5p1/ssh-agent.c 2006-10-23 19:01:16.000000000 +0200 ++++ openssh-4.5p1.nss/ssh-agent.c 2007-05-29 11:55:54.000000000 +0200 +@@ -79,6 +79,10 @@ + #include "scard.h" + #endif + ++#ifdef HAVE_LIBNSS ++#include "nsskeys.h" ++#endif ++ + #if defined(HAVE_SYS_PRCTL_H) + #include /* For prctl() and PR_SET_DUMPABLE */ + #endif +@@ -690,6 +694,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); ++ /* 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 +@@ -785,6 +897,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 -urpN openssh-4.5p1/ssh.c openssh-4.5p1.nss/ssh.c +--- openssh-4.5p1/ssh.c 2006-10-23 19:01:16.000000000 +0200 ++++ openssh-4.5p1.nss/ssh.c 2007-06-20 15:45:40.000000000 +0200 +@@ -104,6 +104,9 @@ + #ifdef SMARTCARD + #include "scard.h" + #endif ++#ifdef HAVE_LIBNSS ++#include "nsskeys.h" ++#endif + + extern char *__progname; + +@@ -1227,9 +1230,12 @@ load_public_identity_files(void) + int i = 0; + Key *public; + struct passwd *pw; +-#ifdef SMARTCARD ++#if defined(SMARTCARD) || defined(HAVE_LIBNSS) + Key **keys; ++#endif + ++ debug("loaded %d keys", options.num_identity_files); ++#ifdef SMARTCARD + if (options.smartcard_device != NULL && + options.num_identity_files < SSH_MAX_IDENTITY_FILES && + (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) { +@@ -1250,6 +1256,27 @@ 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)) != 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"); + if (gethostname(thishost, sizeof(thishost)) == -1) +@@ -1269,6 +1296,7 @@ load_public_identity_files(void) + options.identity_files[i] = filename; + options.identity_keys[i] = public; + } ++ debug("loaded %d keys", options.num_identity_files); + } + + static void +diff -urpN openssh-4.5p1/ssh-dss.c openssh-4.5p1.nss/ssh-dss.c +--- openssh-4.5p1/ssh-dss.c 2006-11-07 13:14:42.000000000 +0100 ++++ openssh-4.5p1.nss/ssh-dss.c 2007-05-25 15:45:19.000000000 +0200 +@@ -39,6 +39,10 @@ + #include "log.h" + #include "key.h" + ++#ifdef HAVE_LIBNSS ++#include ++#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 -urpN openssh-4.5p1/ssh-keygen.c openssh-4.5p1.nss/ssh-keygen.c +--- openssh-4.5p1/ssh-keygen.c 2006-11-07 13:14:42.000000000 +0100 ++++ openssh-4.5p1.nss/ssh-keygen.c 2007-06-20 18:24:40.000000000 +0200 +@@ -52,6 +52,11 @@ + #include "scard.h" + #endif + ++#ifdef HAVE_LIBNSS ++#include ++#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 +@@ -500,6 +505,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); ++ 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) + { +@@ -1057,7 +1082,8 @@ main(int ac, char **av) + 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; +@@ -1091,7 +1117,7 @@ main(int ac, char **av) + } + + 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 = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); +@@ -1131,6 +1157,10 @@ main(int ac, char **av) + case 'g': + print_generic = 1; + break; ++ case 'n': ++ use_nss = 1; ++ download = 1; ++ break; + case 'P': + identity_passphrase = optarg; + break; +@@ -1162,10 +1192,10 @@ main(int ac, char **av) + 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': +@@ -1270,6 +1300,17 @@ main(int ac, char **av) + 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 -urpN openssh-4.5p1/ssh-rsa.c openssh-4.5p1.nss/ssh-rsa.c +--- openssh-4.5p1/ssh-rsa.c 2006-09-01 07:38:37.000000000 +0200 ++++ openssh-4.5p1.nss/ssh-rsa.c 2007-05-25 15:44:57.000000000 +0200 +@@ -32,6 +32,10 @@ + #include "compat.h" + #include "ssh.h" + ++#ifdef HAVE_LIBNSS ++#include ++#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"); diff --git a/openssh.spec b/openssh.spec index 517ac46..2f0b4d0 100644 --- a/openssh.spec +++ b/openssh.spec @@ -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.5p1 -Release: 6%{?dist}%{?rescue_rel} +Release: 7%{?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 @@ -90,6 +93,7 @@ Patch44: openssh-4.3p2-allow-ip-opts.patch Patch48: openssh-4.3p2-pam-session.patch Patch49: openssh-4.3p2-gssapi-canohost.patch Patch50: openssh-4.5p1-mls.patch +Patch51: openssh-4.5p1-nss-keys.patch License: BSD Group: Applications/Internet BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -115,7 +119,7 @@ BuildRequires: autoconf, automake, openssl-devel, perl, zlib-devel BuildRequires: audit-libs-devel BuildRequires: util-linux, groff, man BuildRequires: pam-devel -BuildRequires: tcp_wrappers-devel +#BuildRequires: tcp_wrappers-devel %if %{kerberos5} BuildRequires: krb5-devel @@ -217,6 +221,7 @@ an X11 passphrase dialog for OpenSSH. %patch48 -p1 -b .pam-sesssion %patch49 -p1 -b .canohost %patch50 -p1 -b .mls +%patch51 -p1 -b .nss-keys autoreconf @@ -259,6 +264,9 @@ fi --enable-vendor-patchlevel="FC-%{version}-%{release}" \ --disable-strip \ --without-zlib-version-check \ +%if %{nss} + --with-nss \ +%endif %if %{scard} --with-smartcard \ %endif @@ -342,6 +350,10 @@ rm -f $RPM_BUILD_ROOT/etc/profile.d/gnome-ssh-askpass.* 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 @@ -460,6 +472,10 @@ fi %endif %changelog +* Wed Jun 20 2007 Tomas Mraz - 4.5p1-7 +- experimental NSS keys support +- correctly setup context when empty level requested (#234951) + * Tue Mar 20 2007 Tomas Mraz - 4.5p1-6 - mls level check must be done with default role same as requested