- (djm) [INSTALL Makefile.in README.smartcard configure.ac scard-opensc.c]

[scard.c scard.h pkcs11.h scard/Makefile.in scard/Ssh.bin.uu scard/Ssh.java]
   Remove obsolete smartcard support
This commit is contained in:
Damien Miller 2010-02-12 09:34:22 +11:00
parent d400da5ba8
commit d8f6002272
12 changed files with 1367 additions and 1529 deletions

View File

@ -37,6 +37,9 @@
- jmc@cvs.openbsd.org 2010/02/11 13:23:29
[ssh.1]
libarary -> library;
- (djm) [INSTALL Makefile.in README.smartcard configure.ac scard-opensc.c]
[scard.c scard.h pkcs11.h scard/Makefile.in scard/Ssh.bin.uu scard/Ssh.java]
Remove obsolete smartcard support
20100210
- (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for

View File

@ -208,10 +208,6 @@ are installed.
--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to
real (AF_INET) IPv4 addresses. Works around some quirks on Linux.
--with-opensc=DIR
--with-sectok=DIR allows for OpenSC or sectok smartcard libraries to
be used with OpenSSH. See 'README.smartcard' for more details.
If you need to pass special options to the compiler or linker, you
can specify these as environment variables before running ./configure.
For example:
@ -266,4 +262,4 @@ Please refer to the "reporting bugs" section of the webpage at
http://www.openssh.com/
$Id: INSTALL,v 1.84 2007/08/17 12:52:05 dtucker Exp $
$Id: INSTALL,v 1.85 2010/02/11 22:34:22 djm Exp $

View File

@ -1,4 +1,4 @@
# $Id: Makefile.in,v 1.304 2010/02/11 22:21:02 djm Exp $
# $Id: Makefile.in,v 1.305 2010/02/11 22:34:22 djm Exp $
# uncomment if you run a non bourne compatable shell. Ie. csh
#SHELL = @SH@
@ -72,8 +72,8 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
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 \
kexgex.o kexdhc.o kexgexc.o msg.o progressmeter.o dns.o \
entropy.o gss-genr.o umac.o jpake.o schnorr.o \
ssh-pkcs11.o
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
@ -215,7 +215,6 @@ distclean: regressclean
rm -f survey.sh openbsd-compat/regress/Makefile *~
rm -rf autom4te.cache
(cd openbsd-compat && $(MAKE) distclean)
(cd scard && $(MAKE) distclean)
if test -d pkg ; then \
rm -fr pkg ; \
fi
@ -238,7 +237,6 @@ catman-do:
distprep: catman-do
$(AUTORECONF)
-rm -rf autom4te.cache
(cd scard && $(MAKE) -f Makefile.in distprep)
install: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS) install-files install-sysconf host-key check-config
install-nokeys: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS) install-files install-sysconf
@ -247,10 +245,7 @@ install-nosysconf: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS) insta
check-config:
-$(DESTDIR)$(sbindir)/sshd -t -f $(DESTDIR)$(sysconfdir)/sshd_config
scard-install:
(cd scard && env DESTDIR=$(DESTDIR) $(MAKE) DESTDIR=$(DESTDIR) install)
install-files: scard-install
install-files:
$(srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
$(srcdir)/mkinstalldirs $(DESTDIR)$(sbindir)
$(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)

View File

@ -1,93 +0,0 @@
How to use smartcards with OpenSSH?
OpenSSH contains experimental support for authentication using
Cyberflex smartcards and TODOS card readers, in addition to the cards
with PKCS#15 structure supported by OpenSC. To enable this you
need to:
Using libsectok:
(1) enable sectok support in OpenSSH:
$ ./configure --with-sectok
(2) If you have used a previous version of ssh with your card, you
must remove the old applet and keys.
$ sectok
sectok> login -d
sectok> junload Ssh.bin
sectok> delete 0012
sectok> delete sh
sectok> quit
(3) load the Java Cardlet to the Cyberflex card and set card passphrase:
$ sectok
sectok> login -d
sectok> jload /usr/libdata/ssh/Ssh.bin
sectok> setpass
Enter new AUT0 passphrase:
Re-enter passphrase:
sectok> quit
Do not forget the passphrase. There is no way to
recover if you do.
IMPORTANT WARNING: If you attempt to login with the
wrong passphrase three times in a row, you will
destroy your card.
(4) load a RSA key to the card:
$ ssh-keygen -f /path/to/rsakey -U 1
(where 1 is the reader number, you can also try 0)
In spite of the name, this does not generate a key.
It just loads an already existing key on to the card.
(5) Optional: If you don't want to use a card passphrase, change the
acl on the private key file:
$ sectok
sectok> login -d
sectok> acl 0012 world: w
world: w
AUT0: w inval
sectok> quit
If you do this, anyone who has access to your card
can assume your identity. This is not recommended.
Using OpenSC:
(1) install OpenSC:
Sources and instructions are available from
http://www.opensc.org/
(2) enable OpenSC support in OpenSSH:
$ ./configure --with-opensc[=/path/to/opensc] [options]
(3) load a RSA key to the card:
Not supported yet.
Common operations:
(1) tell the ssh client to use the card reader:
$ ssh -I 1 otherhost
(2) or tell the agent (don't forget to restart) to use the smartcard:
$ ssh-add -s 1
-markus,
Tue Jul 17 23:54:51 CEST 2001
$OpenBSD: README.smartcard,v 1.9 2003/11/21 11:57:02 djm Exp $

View File

@ -1,4 +1,4 @@
# $Id: configure.ac,v 1.441 2010/02/11 22:21:02 djm Exp $
# $Id: configure.ac,v 1.442 2010/02/11 22:34:22 djm Exp $
#
# Copyright (c) 1999-2004 Damien Miller
#
@ -15,7 +15,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org)
AC_REVISION($Revision: 1.441 $)
AC_REVISION($Revision: 1.442 $)
AC_CONFIG_SRCDIR([ssh.c])
AC_CONFIG_HEADER(config.h)
@ -3263,73 +3263,6 @@ if test "x$ac_cv_libc_defines_sys_nerr" = "xyes" ; then
AC_DEFINE(HAVE_SYS_NERR, 1, [Define if your system defines sys_nerr])
fi
SCARD_MSG="no"
# Check whether user wants sectok support
AC_ARG_WITH(sectok,
[ --with-sectok Enable smartcard support using libsectok],
[
if test "x$withval" != "xno" ; then
if test "x$withval" != "xyes" ; then
CPPFLAGS="$CPPFLAGS -I${withval}"
LDFLAGS="$LDFLAGS -L${withval}"
if test ! -z "$need_dash_r" ; then
LDFLAGS="$LDFLAGS -R${withval}"
fi
if test ! -z "$blibpath" ; then
blibpath="$blibpath:${withval}"
fi
fi
AC_CHECK_HEADERS(sectok.h)
if test "$ac_cv_header_sectok_h" != yes; then
AC_MSG_ERROR(Can't find sectok.h)
fi
AC_CHECK_LIB(sectok, sectok_open)
if test "$ac_cv_lib_sectok_sectok_open" != yes; then
AC_MSG_ERROR(Can't find libsectok)
fi
AC_DEFINE(SMARTCARD, 1,
[Define if you want smartcard support])
AC_DEFINE(USE_SECTOK, 1,
[Define if you want smartcard support
using sectok])
SCARD_MSG="yes, using sectok"
fi
]
)
# Check whether user wants OpenSC support
OPENSC_CONFIG="no"
AC_ARG_WITH(opensc,
[ --with-opensc[[=PFX]] Enable smartcard support using OpenSC (optionally in PATH)],
[
if test "x$withval" != "xno" ; then
AC_PATH_PROG(PKGCONFIG, pkg-config, no)
AC_MSG_CHECKING(how to get opensc config)
if test "x$withval" != "xyes" -a "x$PKGCONFIG" = "xno"; then
OPENSC_CONFIG="$withval/bin/opensc-config"
elif test -f "$withval/src/libopensc/libopensc.pc"; then
OPENSC_CONFIG="$PKGCONFIG $withval/src/libopensc/libopensc.pc"
elif test "x$PKGCONFIG" != "xno"; then
OPENSC_CONFIG="$PKGCONFIG libopensc"
else
AC_PATH_PROG(OPENSC_CONFIG, opensc-config, no)
fi
AC_MSG_RESULT($OPENSC_CONFIG)
if test "$OPENSC_CONFIG" != "no"; then
LIBOPENSC_CFLAGS=`$OPENSC_CONFIG --cflags`
LIBOPENSC_LIBS=`$OPENSC_CONFIG --libs`
CPPFLAGS="$CPPFLAGS $LIBOPENSC_CFLAGS"
LIBS="$LIBS $LIBOPENSC_LIBS"
AC_DEFINE(SMARTCARD)
AC_DEFINE(USE_OPENSC, 1,
[Define if you want smartcard support
using OpenSC])
SCARD_MSG="yes, using OpenSC"
fi
fi
]
)
# Check libraries needed by DNS fingerprint support
AC_SEARCH_LIBS(getrrsetbyname, resolv,
[AC_DEFINE(HAVE_GETRRSETBYNAME, 1,
@ -4204,7 +4137,7 @@ fi
AC_EXEEXT
AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \
openbsd-compat/Makefile openbsd-compat/regress/Makefile \
scard/Makefile ssh_prng_cmds survey.sh])
ssh_prng_cmds survey.sh])
AC_OUTPUT
# Print summary of options

1356
pkcs11.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,532 +0,0 @@
/*
* Copyright (c) 2002 Juha Yrjölä. All rights reserved.
* Copyright (c) 2001 Markus Friedl.
*
* 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"
#if defined(SMARTCARD) && defined(USE_OPENSC)
#include <sys/types.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <stdarg.h>
#include <string.h>
#include <opensc/opensc.h>
#include <opensc/pkcs15.h>
#include "key.h"
#include "log.h"
#include "xmalloc.h"
#include "misc.h"
#include "scard.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
#define USE_ENGINE
#define RSA_get_default_method RSA_get_default_openssl_method
#else
#endif
#ifdef USE_ENGINE
#include <openssl/engine.h>
#define sc_get_rsa sc_get_engine
#else
#define sc_get_rsa sc_get_rsa_method
#endif
static int sc_reader_id;
static sc_context_t *ctx = NULL;
static sc_card_t *card = NULL;
static sc_pkcs15_card_t *p15card = NULL;
static char *sc_pin = NULL;
struct sc_priv_data
{
struct sc_pkcs15_id cert_id;
int ref_count;
};
void
sc_close(void)
{
if (p15card) {
sc_pkcs15_unbind(p15card);
p15card = NULL;
}
if (card) {
sc_disconnect_card(card, 0);
card = NULL;
}
if (ctx) {
sc_release_context(ctx);
ctx = NULL;
}
}
static int
sc_init(void)
{
int r;
r = sc_establish_context(&ctx, "openssh");
if (r)
goto err;
if (sc_reader_id >= ctx->reader_count) {
r = SC_ERROR_NO_READERS_FOUND;
error("Illegal reader number %d (max %d)", sc_reader_id,
ctx->reader_count -1);
goto err;
}
r = sc_connect_card(ctx->reader[sc_reader_id], 0, &card);
if (r)
goto err;
r = sc_pkcs15_bind(card, &p15card);
if (r)
goto err;
return 0;
err:
sc_close();
return r;
}
/* private key operations */
static int
sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out,
unsigned int usage)
{
int r;
struct sc_priv_data *priv;
struct sc_pkcs15_object *key_obj;
struct sc_pkcs15_prkey_info *key;
struct sc_pkcs15_object *pin_obj;
struct sc_pkcs15_pin_info *pin;
priv = (struct sc_priv_data *) RSA_get_app_data(rsa);
if (priv == NULL)
return -1;
if (p15card == NULL) {
sc_close();
r = sc_init();
if (r) {
error("SmartCard init failed: %s", sc_strerror(r));
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id_usage(p15card, &priv->cert_id,
usage, &key_obj);
if (r) {
error("Unable to find private key from SmartCard: %s",
sc_strerror(r));
goto err;
}
key = key_obj->data;
r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id,
&pin_obj);
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
/* no pin required */
r = sc_lock(card);
if (r) {
error("Unable to lock smartcard: %s", sc_strerror(r));
goto err;
}
*key_obj_out = key_obj;
return 0;
} else if (r) {
error("Unable to find PIN object from SmartCard: %s",
sc_strerror(r));
goto err;
}
pin = pin_obj->data;
r = sc_lock(card);
if (r) {
error("Unable to lock smartcard: %s", sc_strerror(r));
goto err;
}
if (sc_pin != NULL) {
r = sc_pkcs15_verify_pin(p15card, pin, sc_pin,
strlen(sc_pin));
if (r) {
sc_unlock(card);
error("PIN code verification failed: %s",
sc_strerror(r));
goto err;
}
}
*key_obj_out = key_obj;
return 0;
err:
sc_close();
return -1;
}
#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \
SC_PKCS15_PRKEY_USAGE_UNWRAP
static int
sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
struct sc_pkcs15_object *key_obj;
int r;
if (padding != RSA_PKCS1_PADDING)
return -1;
r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_DECRYPT);
if (r)
return -1;
r = sc_pkcs15_decipher(p15card, key_obj, SC_ALGORITHM_RSA_PAD_PKCS1,
from, flen, to, flen);
sc_unlock(card);
if (r < 0) {
error("sc_pkcs15_decipher() failed: %s", sc_strerror(r));
goto err;
}
return r;
err:
sc_close();
return -1;
}
#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
static int
sc_sign(int type, u_char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa)
{
struct sc_pkcs15_object *key_obj;
int r;
unsigned long flags = 0;
/* XXX: sc_prkey_op_init will search for a pkcs15 private
* key object with the sign or signrecover usage flag set.
* If the signing key has only the non-repudiation flag set
* the key will be rejected as using a non-repudiation key
* for authentication is not recommended. Note: This does not
* prevent the use of a non-repudiation key for authentication
* if the sign or signrecover flag is set as well.
*/
r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_SIGN);
if (r)
return -1;
/* FIXME: length of sigret correct? */
/* FIXME: check 'type' and modify flags accordingly */
flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1;
r = sc_pkcs15_compute_signature(p15card, key_obj, flags,
m, m_len, sigret, RSA_size(rsa));
sc_unlock(card);
if (r < 0) {
error("sc_pkcs15_compute_signature() failed: %s",
sc_strerror(r));
goto err;
}
*siglen = r;
return 1;
err:
sc_close();
return 0;
}
static int
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
error("Private key encryption not supported");
return -1;
}
/* called on free */
static int (*orig_finish)(RSA *rsa) = NULL;
static int
sc_finish(RSA *rsa)
{
struct sc_priv_data *priv;
priv = RSA_get_app_data(rsa);
priv->ref_count--;
if (priv->ref_count == 0) {
free(priv);
sc_close();
}
if (orig_finish)
orig_finish(rsa);
return 1;
}
/* engine for overloading private key operations */
static RSA_METHOD *
sc_get_rsa_method(void)
{
static RSA_METHOD smart_rsa;
const RSA_METHOD *def = RSA_get_default_method();
/* use the OpenSSL version */
memcpy(&smart_rsa, def, sizeof(smart_rsa));
smart_rsa.name = "opensc";
/* overload */
smart_rsa.rsa_priv_enc = sc_private_encrypt;
smart_rsa.rsa_priv_dec = sc_private_decrypt;
smart_rsa.rsa_sign = sc_sign;
/* save original */
orig_finish = def->finish;
smart_rsa.finish = sc_finish;
return &smart_rsa;
}
#ifdef USE_ENGINE
static ENGINE *
sc_get_engine(void)
{
static ENGINE *smart_engine = NULL;
if ((smart_engine = ENGINE_new()) == NULL)
fatal("ENGINE_new failed");
ENGINE_set_id(smart_engine, "opensc");
ENGINE_set_name(smart_engine, "OpenSC");
ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
ENGINE_set_RAND(smart_engine, RAND_SSLeay());
ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
return smart_engine;
}
#endif
static void
convert_rsa_to_rsa1(Key * in, Key * out)
{
struct sc_priv_data *priv;
out->rsa->flags = in->rsa->flags;
out->flags = in->flags;
RSA_set_method(out->rsa, RSA_get_method(in->rsa));
BN_copy(out->rsa->n, in->rsa->n);
BN_copy(out->rsa->e, in->rsa->e);
priv = RSA_get_app_data(in->rsa);
priv->ref_count++;
RSA_set_app_data(out->rsa, priv);
return;
}
static int
sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj)
{
int r;
sc_pkcs15_cert_t *cert = NULL;
struct sc_priv_data *priv = NULL;
sc_pkcs15_cert_info_t *cinfo = cert_obj->data;
X509 *x509 = NULL;
EVP_PKEY *pubkey = NULL;
u8 *p;
char *tmp;
debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]);
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
if (r) {
logit("Certificate read failed: %s", sc_strerror(r));
goto err;
}
x509 = X509_new();
if (x509 == NULL) {
r = -1;
goto err;
}
p = cert->data;
if (!d2i_X509(&x509, &p, cert->data_len)) {
logit("Unable to parse X.509 certificate");
r = -1;
goto err;
}
sc_pkcs15_free_certificate(cert);
cert = NULL;
pubkey = X509_get_pubkey(x509);
X509_free(x509);
x509 = NULL;
if (pubkey->type != EVP_PKEY_RSA) {
logit("Public key is of unknown type");
r = -1;
goto err;
}
k->rsa = EVP_PKEY_get1_RSA(pubkey);
EVP_PKEY_free(pubkey);
k->rsa->flags |= RSA_FLAG_SIGN_VER;
RSA_set_method(k->rsa, sc_get_rsa_method());
priv = xmalloc(sizeof(struct sc_priv_data));
priv->cert_id = cinfo->id;
priv->ref_count = 1;
RSA_set_app_data(k->rsa, priv);
k->flags = KEY_FLAG_EXT;
tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
debug("fingerprint %d %s", key_size(k), tmp);
xfree(tmp);
return 0;
err:
if (cert)
sc_pkcs15_free_certificate(cert);
if (pubkey)
EVP_PKEY_free(pubkey);
if (x509)
X509_free(x509);
return r;
}
Key **
sc_get_keys(const char *id, const char *pin)
{
Key *k, **keys;
int i, r, real_count = 0, key_count;
sc_pkcs15_id_t cert_id;
sc_pkcs15_object_t *certs[32];
char *buf = xstrdup(id), *p;
debug("sc_get_keys called: id = %s", id);
if (sc_pin != NULL)
xfree(sc_pin);
sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
cert_id.len = 0;
if ((p = strchr(buf, ':')) != NULL) {
*p = 0;
p++;
sc_pkcs15_hex_string_to_id(p, &cert_id);
}
r = sscanf(buf, "%d", &sc_reader_id);
xfree(buf);
if (r != 1)
goto err;
if (p15card == NULL) {
sc_close();
r = sc_init();
if (r) {
error("Smartcard init failed: %s", sc_strerror(r));
goto err;
}
}
if (cert_id.len) {
r = sc_pkcs15_find_cert_by_id(p15card, &cert_id, &certs[0]);
if (r < 0)
goto err;
key_count = 1;
} else {
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509,
certs, 32);
if (r == 0) {
logit("No certificates found on smartcard");
r = -1;
goto err;
} else if (r < 0) {
error("Certificate enumeration failed: %s",
sc_strerror(r));
goto err;
}
key_count = r;
}
if (key_count > 1024)
fatal("Too many keys (%u), expected <= 1024", key_count);
keys = xcalloc(key_count * 2 + 1, sizeof(Key *));
for (i = 0; i < key_count; i++) {
sc_pkcs15_object_t *tmp_obj = NULL;
cert_id = ((sc_pkcs15_cert_info_t *)(certs[i]->data))->id;
if (sc_pkcs15_find_prkey_by_id(p15card, &cert_id, &tmp_obj))
/* skip the public key (certificate) if no
* corresponding private key is present */
continue;
k = key_new(KEY_RSA);
if (k == NULL)
break;
r = sc_read_pubkey(k, certs[i]);
if (r) {
error("sc_read_pubkey failed: %s", sc_strerror(r));
key_free(k);
continue;
}
keys[real_count] = k;
real_count++;
k = key_new(KEY_RSA1);
if (k == NULL)
break;
convert_rsa_to_rsa1(keys[real_count-1], k);
keys[real_count] = k;
real_count++;
}
keys[real_count] = NULL;
return keys;
err:
sc_close();
return NULL;
}
int
sc_put_key(Key *prv, const char *id)
{
error("key uploading not yet supported");
return -1;
}
char *
sc_get_key_label(Key *key)
{
int r;
const struct sc_priv_data *priv;
struct sc_pkcs15_object *key_obj;
priv = (const struct sc_priv_data *) RSA_get_app_data(key->rsa);
if (priv == NULL || p15card == NULL) {
logit("SmartCard key not loaded");
/* internal error => return default label */
return xstrdup("smartcard key");
}
r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj);
if (r) {
logit("Unable to find private key from SmartCard: %s",
sc_strerror(r));
return xstrdup("smartcard key");
}
if (key_obj == NULL || key_obj->label == NULL)
/* the optional PKCS#15 label does not exists
* => return the default label */
return xstrdup("smartcard key");
return xstrdup(key_obj->label);
}
#endif /* SMARTCARD */

571
scard.c
View File

@ -1,571 +0,0 @@
/* $OpenBSD: scard.c,v 1.36 2006/11/06 21:25:28 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. 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"
#if defined(SMARTCARD) && defined(USE_SECTOK)
#include <sys/types.h>
#include <sectok.h>
#include <stdarg.h>
#include <string.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "log.h"
#include "misc.h"
#include "scard.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000L
#define USE_ENGINE
#define RSA_get_default_method RSA_get_default_openssl_method
#else
#endif
#ifdef USE_ENGINE
#include <openssl/engine.h>
#define sc_get_rsa sc_get_engine
#else
#define sc_get_rsa sc_get_rsa_method
#endif
#define CLA_SSH 0x05
#define INS_DECRYPT 0x10
#define INS_GET_KEYLENGTH 0x20
#define INS_GET_PUBKEY 0x30
#define INS_GET_RESPONSE 0xc0
#define MAX_BUF_SIZE 256
u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
static int sc_fd = -1;
static char *sc_reader_id = NULL;
static char *sc_pin = NULL;
static int cla = 0x00; /* class */
static void sc_mk_digest(const char *pin, u_char *digest);
static int get_AUT0(u_char *aut0);
static int try_AUT0(void);
/* interface to libsectok */
static int
sc_open(void)
{
int sw;
if (sc_fd >= 0)
return sc_fd;
sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
if (sc_fd < 0) {
error("sectok_open failed: %s", sectok_get_sw(sw));
return SCARD_ERROR_FAIL;
}
if (! sectok_cardpresent(sc_fd)) {
debug("smartcard in reader %s not present, skipping",
sc_reader_id);
sc_close();
return SCARD_ERROR_NOCARD;
}
if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
error("sectok_reset failed: %s", sectok_get_sw(sw));
sc_fd = -1;
return SCARD_ERROR_FAIL;
}
if ((cla = cyberflex_inq_class(sc_fd)) < 0)
cla = 0;
debug("sc_open ok %d", sc_fd);
return sc_fd;
}
static int
sc_enable_applet(void)
{
static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
int sw = 0;
/* select applet id */
sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
if (!sectok_swOK(sw)) {
error("sectok_apdu failed: %s", sectok_get_sw(sw));
sc_close();
return -1;
}
return 0;
}
static int
sc_init(void)
{
int status;
status = sc_open();
if (status == SCARD_ERROR_NOCARD) {
return SCARD_ERROR_NOCARD;
}
if (status < 0) {
error("sc_open failed");
return status;
}
if (sc_enable_applet() < 0) {
error("sc_enable_applet failed");
return SCARD_ERROR_APPLET;
}
return 0;
}
static int
sc_read_pubkey(Key * k)
{
u_char buf[2], *n;
char *p;
int len, sw, status = -1;
len = sw = 0;
n = NULL;
if (sc_fd < 0) {
if (sc_init() < 0)
goto err;
}
/* get key size */
sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
sizeof(buf), buf, &sw);
if (!sectok_swOK(sw)) {
error("could not obtain key length: %s", sectok_get_sw(sw));
goto err;
}
len = (buf[0] << 8) | buf[1];
len /= 8;
debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
n = xmalloc(len);
/* get n */
sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
if (sw == 0x6982) {
if (try_AUT0() < 0)
goto err;
sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
}
if (!sectok_swOK(sw)) {
error("could not obtain public key: %s", sectok_get_sw(sw));
goto err;
}
debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
error("c_read_pubkey: BN_bin2bn failed");
goto err;
}
/* currently the java applet just stores 'n' */
if (!BN_set_word(k->rsa->e, 35)) {
error("c_read_pubkey: BN_set_word(e, 35) failed");
goto err;
}
status = 0;
p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
debug("fingerprint %u %s", key_size(k), p);
xfree(p);
err:
if (n != NULL)
xfree(n);
sc_close();
return status;
}
/* private key operations */
static int
sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
u_char *padded = NULL;
int sw, len, olen, status = -1;
debug("sc_private_decrypt called");
olen = len = sw = 0;
if (sc_fd < 0) {
status = sc_init();
if (status < 0)
goto err;
}
if (padding != RSA_PKCS1_PADDING)
goto err;
len = BN_num_bytes(rsa->n);
padded = xmalloc(len);
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
if (sw == 0x6982) {
if (try_AUT0() < 0)
goto err;
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
}
if (!sectok_swOK(sw)) {
error("sc_private_decrypt: INS_DECRYPT failed: %s",
sectok_get_sw(sw));
goto err;
}
olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
len);
err:
if (padded)
xfree(padded);
sc_close();
return (olen >= 0 ? olen : status);
}
static int
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
u_char *padded = NULL;
int sw, len, status = -1;
len = sw = 0;
if (sc_fd < 0) {
status = sc_init();
if (status < 0)
goto err;
}
if (padding != RSA_PKCS1_PADDING)
goto err;
debug("sc_private_encrypt called");
len = BN_num_bytes(rsa->n);
padded = xmalloc(len);
if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) {
error("RSA_padding_add_PKCS1_type_1 failed");
goto err;
}
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
if (sw == 0x6982) {
if (try_AUT0() < 0)
goto err;
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
}
if (!sectok_swOK(sw)) {
error("sc_private_encrypt: INS_DECRYPT failed: %s",
sectok_get_sw(sw));
goto err;
}
err:
if (padded)
xfree(padded);
sc_close();
return (len >= 0 ? len : status);
}
/* called on free */
static int (*orig_finish)(RSA *rsa) = NULL;
static int
sc_finish(RSA *rsa)
{
if (orig_finish)
orig_finish(rsa);
sc_close();
return 1;
}
/* engine for overloading private key operations */
static RSA_METHOD *
sc_get_rsa_method(void)
{
static RSA_METHOD smart_rsa;
const RSA_METHOD *def = RSA_get_default_method();
/* use the OpenSSL version */
memcpy(&smart_rsa, def, sizeof(smart_rsa));
smart_rsa.name = "sectok";
/* overload */
smart_rsa.rsa_priv_enc = sc_private_encrypt;
smart_rsa.rsa_priv_dec = sc_private_decrypt;
/* save original */
orig_finish = def->finish;
smart_rsa.finish = sc_finish;
return &smart_rsa;
}
#ifdef USE_ENGINE
static ENGINE *
sc_get_engine(void)
{
static ENGINE *smart_engine = NULL;
if ((smart_engine = ENGINE_new()) == NULL)
fatal("ENGINE_new failed");
ENGINE_set_id(smart_engine, "sectok");
ENGINE_set_name(smart_engine, "libsectok");
ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
ENGINE_set_RAND(smart_engine, RAND_SSLeay());
ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
return smart_engine;
}
#endif
void
sc_close(void)
{
if (sc_fd >= 0) {
sectok_close(sc_fd);
sc_fd = -1;
}
}
Key **
sc_get_keys(const char *id, const char *pin)
{
Key *k, *n, **keys;
int status, nkeys = 2;
if (sc_reader_id != NULL)
xfree(sc_reader_id);
sc_reader_id = xstrdup(id);
if (sc_pin != NULL)
xfree(sc_pin);
sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
k = key_new(KEY_RSA);
if (k == NULL) {
return NULL;
}
status = sc_read_pubkey(k);
if (status == SCARD_ERROR_NOCARD) {
key_free(k);
return NULL;
}
if (status < 0) {
error("sc_read_pubkey failed");
key_free(k);
return NULL;
}
keys = xcalloc((nkeys+1), sizeof(Key *));
n = key_new(KEY_RSA1);
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
fatal("sc_get_keys: BN_copy failed");
RSA_set_method(n->rsa, sc_get_rsa());
n->flags |= KEY_FLAG_EXT;
keys[0] = n;
n = key_new(KEY_RSA);
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
fatal("sc_get_keys: BN_copy failed");
RSA_set_method(n->rsa, sc_get_rsa());
n->flags |= KEY_FLAG_EXT;
keys[1] = n;
keys[2] = NULL;
key_free(k);
return keys;
}
#define NUM_RSA_KEY_ELEMENTS 5+1
#define COPY_RSA_KEY(x, i) \
do { \
len = BN_num_bytes(prv->rsa->x); \
elements[i] = xmalloc(len); \
debug("#bytes %d", len); \
if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \
goto done; \
} while (0)
static void
sc_mk_digest(const char *pin, u_char *digest)
{
const EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, pin, strlen(pin));
EVP_DigestFinal(&md, digest, NULL);
}
static int
get_AUT0(u_char *aut0)
{
char *pass;
pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
if (pass == NULL)
return -1;
if (!strcmp(pass, "-")) {
memcpy(aut0, DEFAUT0, sizeof DEFAUT0);
return 0;
}
sc_mk_digest(pass, aut0);
memset(pass, 0, strlen(pass));
xfree(pass);
return 0;
}
static int
try_AUT0(void)
{
u_char aut0[EVP_MAX_MD_SIZE];
/* permission denied; try PIN if provided */
if (sc_pin && strlen(sc_pin) > 0) {
sc_mk_digest(sc_pin, aut0);
if (cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
error("smartcard passphrase incorrect");
return (-1);
}
} else {
/* try default AUT0 key */
if (cyberflex_verify_AUT0(sc_fd, cla, DEFAUT0, 8) < 0) {
/* default AUT0 key failed; prompt for passphrase */
if (get_AUT0(aut0) < 0 ||
cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
error("smartcard passphrase incorrect");
return (-1);
}
}
}
return (0);
}
int
sc_put_key(Key *prv, const char *id)
{
u_char *elements[NUM_RSA_KEY_ELEMENTS];
u_char key_fid[2];
u_char AUT0[EVP_MAX_MD_SIZE];
int len, status = -1, i, fd = -1, ret;
int sw = 0, cla = 0x00;
for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
elements[i] = NULL;
COPY_RSA_KEY(q, 0);
COPY_RSA_KEY(p, 1);
COPY_RSA_KEY(iqmp, 2);
COPY_RSA_KEY(dmq1, 3);
COPY_RSA_KEY(dmp1, 4);
COPY_RSA_KEY(n, 5);
len = BN_num_bytes(prv->rsa->n);
fd = sectok_friendly_open(id, STONOWAIT, &sw);
if (fd < 0) {
error("sectok_open failed: %s", sectok_get_sw(sw));
goto done;
}
if (! sectok_cardpresent(fd)) {
error("smartcard in reader %s not present", id);
goto done;
}
ret = sectok_reset(fd, 0, NULL, &sw);
if (ret <= 0) {
error("sectok_reset failed: %s", sectok_get_sw(sw));
goto done;
}
if ((cla = cyberflex_inq_class(fd)) < 0) {
error("cyberflex_inq_class failed");
goto done;
}
memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0));
if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
if (get_AUT0(AUT0) < 0 ||
cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
memset(AUT0, 0, sizeof(DEFAUT0));
error("smartcard passphrase incorrect");
goto done;
}
}
memset(AUT0, 0, sizeof(DEFAUT0));
key_fid[0] = 0x00;
key_fid[1] = 0x12;
if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements,
&sw) < 0) {
error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw));
goto done;
}
if (!sectok_swOK(sw))
goto done;
logit("cyberflex_load_rsa_priv done");
key_fid[0] = 0x73;
key_fid[1] = 0x68;
if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5],
&sw) < 0) {
error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw));
goto done;
}
if (!sectok_swOK(sw))
goto done;
logit("cyberflex_load_rsa_pub done");
status = 0;
done:
memset(elements[0], '\0', BN_num_bytes(prv->rsa->q));
memset(elements[1], '\0', BN_num_bytes(prv->rsa->p));
memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp));
memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1));
memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1));
memset(elements[5], '\0', BN_num_bytes(prv->rsa->n));
for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
if (elements[i])
xfree(elements[i]);
if (fd != -1)
sectok_close(fd);
return (status);
}
char *
sc_get_key_label(Key *key)
{
return xstrdup("smartcard key");
}
#endif /* SMARTCARD && USE_SECTOK */

39
scard.h
View File

@ -1,39 +0,0 @@
/* $OpenBSD: scard.h,v 1.14 2006/08/03 03:34:42 deraadt Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. 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 SCARD_H
#define SCARD_H
#define SCARD_ERROR_FAIL -1
#define SCARD_ERROR_NOCARD -2
#define SCARD_ERROR_APPLET -3
Key **sc_get_keys(const char *, const char *);
void sc_close(void);
int sc_put_key(Key *, const char *);
char *sc_get_key_label(Key *);
#endif

View File

@ -1,29 +0,0 @@
# $Id: Makefile.in,v 1.5 2006/10/23 21:44:47 tim Exp $
prefix=@prefix@
datadir=@datadir@
datarootdir=@datarootdir@
srcdir=@srcdir@
top_srcdir=@top_srcdir@
INSTALL=@INSTALL@
VPATH=@srcdir@
all:
#Ssh.bin: Ssh.bin.uu
# uudecode Ssh.bin.uu
clean:
# rm -rf Ssh.bin
distprep:
uudecode Ssh.bin.uu
distclean: clean
rm -f Makefile *~
install: $(srcdir)/Ssh.bin
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir)
$(INSTALL) -m 0644 $(srcdir)/Ssh.bin $(DESTDIR)$(datadir)/Ssh.bin

View File

@ -1,17 +0,0 @@
begin 644 Ssh.bin
M`P)!&P`801X`>``!`E@"`/Y@\`4`_J'P!0!!&T$=`?Z@\`4`01M!'`'^>/,!
M`4$;01X!_G#S%P'^0],1`?Y@\!0`_G/S'0#^<]4``D$;L`4`_F'3``#^8=,%
M`/ZAT`$!_J#0)P'^H],*`?ZCTPD`_G/5"P7^8=,'`OZAT`H`_J#0$@3^:-,@
M`T$;`P`%`/Y@`<P``$$<\@\``$$=\B$``$$>\A```/`0__(%`@8!`0H``&``
M0205!!D)I$L`"0J0`&``*!4$&58``````.P````%____P````.D````0````
M,P```"````#'````,````(T````R````V!4#&0A*``D*;@!@`"@5!QD*`/\]
M(6``1A)*``D*9P!@`"@*/P!@`$LK"1)@`$LK!6``4!P$#00#2@`.#01@`%5@
M`%I@`"@37``>%0@2%0A>`%\($F``9%(`:`H_`&``2RL*<VA@`$LK8`!I"1`U
M(14#`Q)@`&X<!`T$`TL`"P,28`!D4@`.#01@`%5@`%I@`"A2`"X5`PH$`&``
M<RL#!6``9%(`'14#"@$"8`!S*P,%8`!D4@`,4@`)"FT`8``H60``\`+_\@$!
M`0D`"```"I``8``H60#P$__R`0$""0`,``!B01LM7P`\*UD```#P$O_V`0$#
M`0`8```37``>7@`R10`/$UP`'@H`R`D07@`W!%>P!?_R`0$$`@`\```37P``
M$V+^H2U?``5=``H38OZ@+5\`#UT`%!-B_G@M"@0`7P`970`>"@0`8``C10`)
/"F<`8``H$UX`+5D`````
`
end

View File

@ -1,164 +0,0 @@
// $Id: Ssh.java,v 1.3 2002/05/22 04:24:02 djm Exp $
//
// Ssh.java
// SSH / smartcard integration project, smartcard side
//
// Tomoko Fukuzawa, created, Feb., 2000
//
// Naomaru Itoi, modified, Apr., 2000
//
// copyright 2000
// the regents of the university of michigan
// all rights reserved
//
// permission is granted to use, copy, create derivative works
// and redistribute this software and such derivative works
// for any purpose, so long as the name of the university of
// michigan is not used in any advertising or publicity
// pertaining to the use or distribution of this software
// without specific, written prior authorization. if the
// above copyright notice or any other identification of the
// university of michigan is included in any copy of any
// portion of this software, then the disclaimer below must
// also be included.
//
// this software is provided as is, without representation
// from the university of michigan as to its fitness for any
// purpose, and without warranty by the university of
// michigan of any kind, either express or implied, including
// without limitation the implied warranties of
// merchantability and fitness for a particular purpose. the
// regents of the university of michigan shall not be liable
// for any damages, including special, indirect, incidental, or
// consequential damages, with respect to any claim arising
// out of or in connection with the use of the software, even
// if it has been or is hereafter advised of the possibility of
// such damages.
import javacard.framework.*;
import javacardx.framework.*;
import javacardx.crypto.*;
public class Ssh extends javacard.framework.Applet
{
// Change this when the applet changes; hi byte is major, low byte is minor
static final short applet_version = (short)0x0102;
/* constants declaration */
// code of CLA byte in the command APDU header
static final byte Ssh_CLA =(byte)0x05;
// codes of INS byte in the command APDU header
static final byte DECRYPT = (byte) 0x10;
static final byte GET_KEYLENGTH = (byte) 0x20;
static final byte GET_PUBKEY = (byte) 0x30;
static final byte GET_VERSION = (byte) 0x32;
static final byte GET_RESPONSE = (byte) 0xc0;
static final short keysize = 1024;
static final short root_fid = (short)0x3f00;
static final short privkey_fid = (short)0x0012;
static final short pubkey_fid = (short)(('s'<<8)|'h');
/* instance variables declaration */
AsymKey rsakey;
CyberflexFile file;
CyberflexOS os;
private Ssh()
{
file = new CyberflexFile();
os = new CyberflexOS();
rsakey = new RSA_CRT_PrivateKey (keysize);
if ( ! rsakey.isSupportedLength (keysize) )
ISOException.throwIt (ISO.SW_WRONG_LENGTH);
register();
} // end of the constructor
public boolean select() {
if (!rsakey.isInitialized())
rsakey.setKeyInstance ((short)0xc8, (short)0x10);
return true;
}
public static void install(APDU apdu)
{
new Ssh(); // create a Ssh applet instance (card)
} // end of install method
public static void main(String args[]) {
ISOException.throwIt((short) 0x9000);
}
public void process(APDU apdu)
{
// APDU object carries a byte array (buffer) to
// transfer incoming and outgoing APDU header
// and data bytes between card and CAD
byte buffer[] = apdu.getBuffer();
short size, st;
// verify that if the applet can accept this
// APDU message
// NI: change suggested by Wayne Dyksen, Purdue
if (buffer[ISO.OFFSET_INS] == ISO.INS_SELECT)
ISOException.throwIt(ISO.SW_NO_ERROR);
switch (buffer[ISO.OFFSET_INS]) {
case DECRYPT:
if (buffer[ISO.OFFSET_CLA] != Ssh_CLA)
ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);
//decrypt (apdu);
size = (short) (buffer[ISO.OFFSET_LC] & 0x00FF);
if (apdu.setIncomingAndReceive() != size)
ISOException.throwIt (ISO.SW_WRONG_LENGTH);
// check access; depends on bit 2 (x/a)
file.selectFile(root_fid);
file.selectFile(privkey_fid);
st = os.checkAccess(ACL.EXECUTE);
if (st != ST.ACCESS_CLEARED) {
CyberflexAPDU.prepareSW1SW2(st);
ISOException.throwIt(CyberflexAPDU.getSW1SW2());
}
rsakey.cryptoUpdate (buffer, (short) ISO.OFFSET_CDATA, size,
buffer, (short) ISO.OFFSET_CDATA);
apdu.setOutgoingAndSend ((short) ISO.OFFSET_CDATA, size);
break;
case GET_PUBKEY:
file.selectFile(root_fid); // select root
file.selectFile(pubkey_fid); // select public key file
size = (short)(file.getFileSize() - 16);
st = os.readBinaryFile(buffer, (short)0, (short)0, size);
if (st == ST.SUCCESS)
apdu.setOutgoingAndSend((short)0, size);
else {
CyberflexAPDU.prepareSW1SW2(st);
ISOException.throwIt(CyberflexAPDU.getSW1SW2());
}
break;
case GET_KEYLENGTH:
Util.setShort(buffer, (short)0, keysize);
apdu.setOutgoingAndSend ((short)0, (short)2);
break;
case GET_VERSION:
Util.setShort(buffer, (short)0, applet_version);
apdu.setOutgoingAndSend ((short)0, (short)2);
break;
case GET_RESPONSE:
break;
default:
ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED);
}
} // end of process method
} // end of class Ssh