summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2001-06-26 05:33:37 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2001-06-26 05:33:37 +0000
commit3024dcdf459b8abf443e3ccbeb12e54647b62e92 (patch)
tree2f7eeebc9eea583d86f05f4993b5d4b67005064f
parenta4215ef03263a80bf535b73180ae3429a8d31d3d (diff)
more smartcard support.
-rw-r--r--usr.bin/ssh/lib/Makefile7
-rw-r--r--usr.bin/ssh/scard.c359
-rw-r--r--usr.bin/ssh/scard.h30
-rw-r--r--usr.bin/ssh/ssh-agent.c118
-rw-r--r--usr.bin/ssh/ssh-agent/Makefile7
-rw-r--r--usr.bin/ssh/ssh-keygen/Makefile7
6 files changed, 523 insertions, 5 deletions
diff --git a/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile
index 0a0b0343171..b807a7040f5 100644
--- a/usr.bin/ssh/lib/Makefile
+++ b/usr.bin/ssh/lib/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.25 2001/06/24 05:35:34 markus Exp $
+# $OpenBSD: Makefile,v 1.26 2001/06/26 05:33:35 markus Exp $
.PATH: ${.CURDIR}/..
@@ -9,6 +9,7 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c \
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
key.c dispatch.c kex.c mac.c uuencode.c misc.c \
rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c \
+ scard.c
NOPROFILE= yes
NOPIC= yes
@@ -26,4 +27,8 @@ SRCS+= radix.c
.endif # AFS
.endif # KERBEROS
+.if (${SMARTCARD:L} == "yes")
+CFLAGS+= -DSMARTCARD
+.endif # SMARTCARD
+
.include <bsd.lib.mk>
diff --git a/usr.bin/ssh/scard.c b/usr.bin/ssh/scard.c
new file mode 100644
index 00000000000..6dbabf546c2
--- /dev/null
+++ b/usr.bin/ssh/scard.c
@@ -0,0 +1,359 @@
+/*
+ * 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.
+ */
+
+#ifdef SMARTCARD
+#include "includes.h"
+RCSID("$OpenBSD: scard.c,v 1.1 2001/06/26 05:33:34 markus Exp $");
+
+#include <openssl/engine.h>
+#include <sectok.h>
+
+#include "key.h"
+#include "log.h"
+#include "xmalloc.h"
+#include "scard.h"
+
+#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
+
+static int sc_fd = -1;
+static int sc_reader_num = 0;
+static int cla = 0x00; /* class */
+
+/* interface to libsectok */
+
+static int
+sc_open(int num)
+{
+ int n;
+ u_char atr[256];
+
+ if (sc_fd >= 0)
+ return sc_fd;
+ sc_reader_num = num;
+
+ sc_fd = scopen(sc_reader_num, 0, NULL);
+ if (sc_fd < 0) {
+ error("scopen failed %d", sc_fd);
+ return sc_fd;
+ }
+ n = screset(sc_fd, atr, NULL);
+ if (n <= 0) {
+ error("screset failed.");
+ sc_fd = -1;
+ return sc_fd;
+ }
+ debug("open ok %d", sc_fd);
+ return sc_fd;
+}
+
+static int
+sc_reset(void)
+{
+ scclose(sc_fd);
+ sc_fd = -1;
+ return sc_open(sc_reader_num);
+}
+
+static int
+selectfile(int fd, int f0, int f1, int verbose)
+{
+ int n, r1, r2, code;
+ u_char buf[2], obuf[256];
+
+ buf[0] = f0;
+ buf[1] = f1;
+ n = scrw(sc_fd, cla, 0xa4, 0, 0, 2, buf, sizeof obuf, obuf, &r1, &r2);
+ if (n < 0) {
+ error("selectfile: scwrite failed");
+ return -2;
+ }
+ if (r1 == 0x90 || r1 == 0x61)
+ code = 0;
+ else if (r1 == 0x6a && r2 == 0x82)
+ /* file not found */
+ code = -1;
+ else
+ code = -2;
+ if (verbose && n > 0)
+ dump_reply(obuf, n, 0, 0);
+ if (verbose || code == -2) {
+ error("%x.%x: %s", f0, f1, get_r1r2s(r1, r2));
+ }
+ return code;
+}
+
+static int
+sc_enable_applet(void)
+{
+ u_char data[MAX_BUF_SIZE];
+ u_char progID[2], contID[2], aid[MAX_BUF_SIZE];
+ int i, len, rv, r1, r2, aid_len;
+
+ len = rv = r1 = r2 = 0;
+ progID[0] = 0x77;
+ progID[1] = 0x77;
+ contID[0] = 0x77;
+ contID[1] = 0x78;
+ aid_len = 5;
+
+ for (i = 0; i < 16; i++)
+ aid[i] = 0x77;
+
+ rv = selectfile(sc_fd, contID[0], contID[1], 0);
+ if (rv < 0) {
+ error("selectfile failed");
+ return -1;
+ }
+ for (i = 0; i < aid_len; i++)
+ data[i] = (u_char) aid[i];
+ rv = scwrite(sc_fd, cla, 0xa4, 0x04, 0, aid_len, data, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ error("selecting the cardlet: ");
+ for (i = 0; i < aid_len; i++) {
+ error("%02x", (u_char) aid[i]);
+ }
+ print_r1r2(r1, r2);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+sc_read_pubkey(Key * k)
+{
+ u_char buf[256];
+ char *p;
+ int len, rv, r1, r2;
+
+ len = rv = r1 = r2 = 0;
+
+ /* get key size */
+ rv = scread(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 2, buf, &r1, &r2);
+ if (rv < 0) {
+ error("could not obtain key length.");
+ return rv;
+ }
+ len = (buf[0] << 8) | buf[1];
+ error("len %d r1 %d r2 %d", len, r1, r2);
+ len /= 8;
+
+ /* get n */
+ rv = scread(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, len, buf, &r1, &r2);
+ if (rv < 0) {
+ error("could not obtain public key");
+ return rv;
+ }
+ debug("len %d r1 %d r2 %d", len, r1, r2);
+ BN_bin2bn(buf, len, k->rsa->n);
+
+ /* currently the java applet just stores 'n' */
+ BN_set_word(k->rsa->e, 35); /* XXX */
+
+ p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+ debug("fingerprint %d %s", key_size(k), p);
+ xfree(p);
+
+ return 0;
+}
+
+/* private key operations */
+
+static int
+sc_private_decrypt(int flen, unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ int rv, num, r1, r2, olen;
+ u_char *padded = NULL;
+
+ debug("sc_private_decrypt called");
+
+ olen = num = r1 = r2 = 0;
+ if (padding != RSA_PKCS1_PADDING)
+ goto err;
+
+ num = BN_num_bytes(rsa->n);
+ padded = xmalloc(num);
+
+ rv = scwrite(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, num, from, &r1, &r2);
+ if (rv < 0) {
+ error("scwrite() for decrypt failed.");
+ goto err;
+ }
+ if (r1 != 0x90 && r1 != 0x61) {
+ error("INS_DECRYPT: r1 %x r2 %x", r1, r2);
+ goto err;
+ }
+ rv = scread(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, num, padded, &r1, &r2);
+ if (rv < 0) {
+ error("scread() for decrypt failed");
+ goto err;
+ }
+ if (r1 != 0x90 && r1 != 0x61) {
+ error("INS_GET_RESPONSE: r1 %x r2 %x", r1, r2);
+ goto err;
+ }
+ debug("r1 %x r2 %x", r1, r2);
+ olen = RSA_padding_check_PKCS1_type_2(to, num, padded + 1, num - 1, num);
+err:
+ if (padded)
+ xfree(padded);
+ return olen;
+}
+
+
+static int
+sc_private_encrypt(int flen, unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ int rv, i, num, r1, r2;
+ u_char *padded = NULL;
+
+ num = r1 = r2 = 0;
+ if (padding != RSA_PKCS1_PADDING)
+ goto err;
+
+ error("sc_private_encrypt called");
+ num = BN_num_bytes(rsa->n);
+ padded = xmalloc(num);
+ i = RSA_padding_add_PKCS1_type_1(padded, num, from, flen);
+ if (i <= 0) {
+ error("RSA_padding_add_PKCS1_type_1 failed");
+ goto err;
+ }
+ rv = scwrite(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, num, padded, &r1, &r2);
+ if (rv < 0) {
+ error("scwrite() for rsa failed");
+ sc_reset();
+ goto err;
+ }
+ if (r1 != 0x90 && r1 != 0x61) {
+ error("INS_DECRYPT: r1 %x r2 %x", r1, r2);
+ goto err;
+ }
+ rv = scread(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, num, to, &r1, &r2);
+ if (rv < 0) {
+ error("scread() for rsa failed");
+ sc_reset();
+ goto err;
+ }
+ if (r1 != 0x90 && r1 != 0x61) {
+ error("INS_GET_RESPONSE: r1 %x r2 %x", r1, r2);
+ goto err;
+ }
+err:
+ if (padded)
+ xfree(padded);
+ return num;
+}
+
+/* engine for overloading private key operations */
+
+static ENGINE *smart_engine = NULL;
+static RSA_METHOD smart_rsa =
+{
+ "smartcard",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+};
+
+ENGINE *
+sc_get_engine()
+{
+ RSA_METHOD *def;
+
+ def = RSA_get_default_openssl_method();
+
+ /* overload */
+ smart_rsa.rsa_priv_enc = sc_private_encrypt;
+ smart_rsa.rsa_priv_dec = sc_private_decrypt;
+
+ /* just use the OpenSSL version */
+ smart_rsa.rsa_pub_enc = def->rsa_pub_enc;
+ smart_rsa.rsa_pub_dec = def->rsa_pub_dec;
+ smart_rsa.rsa_mod_exp = def->rsa_mod_exp;
+ smart_rsa.bn_mod_exp = def->bn_mod_exp;
+ smart_rsa.init = def->init;
+ smart_rsa.finish = def->finish;
+ smart_rsa.flags = def->flags;
+ smart_rsa.app_data = def->app_data;
+ smart_rsa.rsa_sign = def->rsa_sign;
+ smart_rsa.rsa_verify = def->rsa_verify;
+
+ smart_engine = ENGINE_new();
+
+ ENGINE_set_id(smart_engine, "xxx");
+ ENGINE_set_name(smart_engine, "xxx");
+ ENGINE_set_RSA(smart_engine, &smart_rsa);
+ 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;
+}
+
+Key *
+sc_get_key(int sc_reader_num)
+{
+ Key *k;
+ int rv;
+
+ rv = sc_open (sc_reader_num);
+ if (rv < 0) {
+ error("sc_open failed");
+ return NULL;
+ }
+ rv = sc_enable_applet();
+ if (rv < 0) {
+ error("sc_enable_applet failed");
+ return NULL;
+ }
+ k = key_new(KEY_RSA);
+ if (k == NULL) {
+ return NULL;
+ }
+ rv = sc_read_pubkey (k);
+ if (rv < 0) {
+ error("sc_read_pubkey failed");
+ key_free(k);
+ return NULL;
+ }
+ return k;
+}
+#endif
diff --git a/usr.bin/ssh/scard.h b/usr.bin/ssh/scard.h
new file mode 100644
index 00000000000..3425967b88a
--- /dev/null
+++ b/usr.bin/ssh/scard.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/* $OpenBSD: scard.h,v 1.1 2001/06/26 05:33:34 markus Exp $ */
+
+#include <openssl/engine.h>
+
+Key *sc_get_key(int sc_reader_num);
+ENGINE *sc_get_engine();
diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c
index c529f6d7d58..288eb6914c0 100644
--- a/usr.bin/ssh/ssh-agent.c
+++ b/usr.bin/ssh/ssh-agent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.58 2001/06/26 05:07:43 markus Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.59 2001/06/26 05:33:34 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -36,7 +36,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.58 2001/06/26 05:07:43 markus Exp $");
+RCSID("$OpenBSD: ssh-agent.c,v 1.59 2001/06/26 05:33:34 markus Exp $");
#include <openssl/evp.h>
#include <openssl/md5.h>
@@ -56,6 +56,11 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.58 2001/06/26 05:07:43 markus Exp $");
#include "compat.h"
#include "log.h"
+#ifdef SMARTCARD
+#include <openssl/engine.h>
+#include "scard.h"
+#endif
+
typedef struct {
int fd;
enum {
@@ -435,6 +440,106 @@ send:
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
+
+#ifdef SMARTCARD
+static void
+process_add_smartcard_key (SocketEntry *e)
+{
+ Idtab *tab;
+ Key *n = NULL, *k = NULL;
+ int success = 0;
+ int sc_reader_num = 0;
+
+ sc_reader_num = buffer_get_int(&e->input);
+
+ k = sc_get_key(sc_reader_num);
+ if (k == NULL) {
+ error("sc_get_pubkey failed");
+ goto send;
+ }
+ success = 1;
+
+ tab = idtab_lookup(1);
+ if (lookup_private_key(k, NULL, 1) == NULL) {
+ if (tab->nentries == 0)
+ tab->identities = xmalloc(sizeof(Identity));
+ else
+ tab->identities = xrealloc(tab->identities,
+ (tab->nentries + 1) * sizeof(Identity));
+ n = key_new(KEY_RSA1);
+ BN_copy(n->rsa->n, k->rsa->n);
+ BN_copy(n->rsa->e, k->rsa->e);
+ RSA_set_method(n->rsa, sc_get_engine());
+ tab->identities[tab->nentries].key = n;
+ tab->identities[tab->nentries].comment =
+ xstrdup("rsa1 smartcard");
+ tab->nentries++;
+ }
+ tab = idtab_lookup(2);
+ if (lookup_private_key(k, NULL, 2) == NULL) {
+ if (tab->nentries == 0)
+ tab->identities = xmalloc(sizeof(Identity));
+ else
+ tab->identities = xrealloc(tab->identities,
+ (tab->nentries + 1) * sizeof(Identity));
+ n = key_new(KEY_RSA);
+ BN_copy(n->rsa->n, k->rsa->n);
+ BN_copy(n->rsa->e, k->rsa->e);
+ RSA_set_method(n->rsa, sc_get_engine());
+ tab->identities[tab->nentries].key = n;
+ tab->identities[tab->nentries].comment =
+ xstrdup("rsa smartcard");
+ tab->nentries++;
+ }
+ key_free(k);
+send:
+ buffer_put_int(&e->output, 1);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_smartcard_key(SocketEntry *e)
+{
+ Key *k = NULL, *private;
+ int idx;
+ int success = 0;
+ int sc_reader_num = 0;
+
+ sc_reader_num = buffer_get_int(&e->input);
+
+ if ((k = sc_get_key(sc_reader_num)) == NULL) {
+ error("sc_get_pubkey failed");
+ } else {
+ private = lookup_private_key(k, &idx, 1);
+ if (private != NULL) {
+ Idtab *tab = idtab_lookup(1);
+ key_free(tab->identities[idx].key);
+ xfree(tab->identities[idx].comment);
+ if (idx != tab->nentries)
+ tab->identities[idx] = tab->identities[tab->nentries];
+ tab->nentries--;
+ success = 1;
+ }
+ private = lookup_private_key(k, &idx, 2);
+ if (private != NULL) {
+ Idtab *tab = idtab_lookup(2);
+ key_free(tab->identities[idx].key);
+ xfree(tab->identities[idx].comment);
+ if (idx != tab->nentries)
+ tab->identities[idx] = tab->identities[tab->nentries];
+ tab->nentries--;
+ success = 1;
+ }
+ key_free(k);
+ }
+
+ buffer_put_int(&e->output, 1);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif
+
/* dispatch incoming messages */
static void
@@ -458,6 +563,7 @@ process_message(SocketEntry *e)
buffer_consume(&e->input, 4);
type = buffer_get_char(&e->input);
+ debug("type %d", type);
switch (type) {
/* ssh1 */
case SSH_AGENTC_RSA_CHALLENGE:
@@ -491,6 +597,14 @@ process_message(SocketEntry *e)
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e, 2);
break;
+#ifdef SMARTCARD
+ case SSH_AGENTC_ADD_SMARTCARD_KEY:
+ process_add_smartcard_key(e);
+ break;
+ case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
+ process_remove_smartcard_key(e);
+ break;
+#endif
default:
/* Unknown message. Respond with failure. */
error("Unknown message %d", type);
diff --git a/usr.bin/ssh/ssh-agent/Makefile b/usr.bin/ssh/ssh-agent/Makefile
index e1a2e2c6cbf..c397bf1ed1d 100644
--- a/usr.bin/ssh/ssh-agent/Makefile
+++ b/usr.bin/ssh/ssh-agent/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.17 2001/03/04 00:51:25 markus Exp $
+# $OpenBSD: Makefile,v 1.18 2001/06/26 05:33:35 markus Exp $
.PATH: ${.CURDIR}/..
@@ -16,3 +16,8 @@ SRCS= ssh-agent.c
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}
+
+.if (${SMARTCARD:L} == "yes")
+CFLAGS+= -DSMARTCARD
+LDADD+= -lsectok
+.endif # SMARTCARD
diff --git a/usr.bin/ssh/ssh-keygen/Makefile b/usr.bin/ssh/ssh-keygen/Makefile
index b7c115169c8..2e6c112822e 100644
--- a/usr.bin/ssh/ssh-keygen/Makefile
+++ b/usr.bin/ssh/ssh-keygen/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.17 2001/03/04 00:51:26 markus Exp $
+# $OpenBSD: Makefile,v 1.18 2001/06/26 05:33:36 markus Exp $
.PATH: ${.CURDIR}/..
@@ -16,3 +16,8 @@ SRCS= ssh-keygen.c
LDADD+= -lcrypto
DPADD+= ${LIBCRYPTO}
+
+.if (${SMARTCARD:L} == "yes")
+CFLAGS+= -DSMARTCARD
+LDADD+= -lsectok
+.endif # SMARTCARD