summaryrefslogtreecommitdiff
path: root/usr.bin/sectok
diff options
context:
space:
mode:
authorJim Rees <rees@cvs.openbsd.org>2001-06-27 19:41:47 +0000
committerJim Rees <rees@cvs.openbsd.org>2001-06-27 19:41:47 +0000
commit59f7b0f9c704dfafb40649b8ca882cb927015e05 (patch)
tree7f78cf385966c87a50659c2eb87e7f056fe45857 /usr.bin/sectok
parent380782c0107ce913906c07d3c9746aeacfc58256 (diff)
sectok control program
Diffstat (limited to 'usr.bin/sectok')
-rw-r--r--usr.bin/sectok/Makefile9
-rw-r--r--usr.bin/sectok/cmds.c323
-rw-r--r--usr.bin/sectok/cyberflex.c771
-rw-r--r--usr.bin/sectok/main.c133
-rw-r--r--usr.bin/sectok/sc.h59
-rw-r--r--usr.bin/sectok/sectok.1122
6 files changed, 1417 insertions, 0 deletions
diff --git a/usr.bin/sectok/Makefile b/usr.bin/sectok/Makefile
new file mode 100644
index 00000000000..a56de725f5e
--- /dev/null
+++ b/usr.bin/sectok/Makefile
@@ -0,0 +1,9 @@
+# $OpenBSD: Makefile,v 1.1 2001/06/27 19:41:45 rees Exp $
+
+PROG= sectok
+SRCS= main.c cmds.c cyberflex.c
+LDADD= -lsectok -lcrypto
+
+CFLAGS+=-Wall
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sectok/cmds.c b/usr.bin/sectok/cmds.c
new file mode 100644
index 00000000000..44b39d627d8
--- /dev/null
+++ b/usr.bin/sectok/cmds.c
@@ -0,0 +1,323 @@
+/* $Id: cmds.c,v 1.1 2001/06/27 19:41:45 rees Exp $ */
+
+/*
+ * Smartcard commander.
+ * Written by Jim Rees and others at University of Michigan.
+ */
+
+/*
+copyright 2001
+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.
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <sectok.h>
+
+#include "sc.h"
+
+#define CARDIOSIZE 200
+
+struct {
+ char *cmd;
+ int (*action) (int ac, char *av[]);
+} dispatch_table[] = {
+ /* Non-card commands */
+ { "help", help },
+ { "?", help },
+ { "reset", reset },
+ { "r", reset },
+ { "open", reset },
+ { "close", dclose },
+ { "quit", quit },
+ { "q", quit },
+
+ /* 7816-4 commands */
+ { "apdu", apdu },
+ { "a", apdu },
+ { "fid", selfid },
+ { "f", selfid },
+ { "class", class },
+ { "read", dread },
+ { "write", dwrite },
+
+ /* Cyberflex commands */
+ { "ls", ls },
+ { "jdefault", jdefault },
+ { "jatr", jatr },
+ { "jdata", jdata },
+ { "jaut", jaut },
+ { "jload", jload },
+ { "junload", junload },
+ { "jselect", jselect },
+ { "jdeselect", jdeselect },
+ { NULL, NULL }
+};
+/*
+ { "", },
+*/
+
+int dispatch(int ac, char *av[])
+{
+ int i;
+
+ for (i = 0; dispatch_table[i].cmd; i++) {
+ if (!strcmp(av[0], dispatch_table[i].cmd)) {
+ (dispatch_table[i].action) (ac, av);
+ break;
+ }
+ }
+ if (!dispatch_table[i].cmd) {
+ printf("unknown command \"%s\"\n", av[0]);
+ return -1;
+ }
+ return 0;
+}
+
+int help(int ac, char *av[])
+{
+ int i;
+
+ for (i = 0; dispatch_table[i].cmd; i++) {
+ if (strlen(dispatch_table[i].cmd) > 1)
+ printf("%s\n", dispatch_table[i].cmd);
+ }
+
+ return 0;
+}
+
+int reset(int ac, char *av[])
+{
+ int i, n, port = 0, oflags = SCODSR, rflags = 0, err;
+ unsigned char buf[34];
+
+ optind = optreset = 1;
+
+ while ((i = getopt(ac, av, "1234ivf")) != -1) {
+ switch (i) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ port = i - '1';
+ break;
+ case 'i':
+ oflags &= ~SCODSR;
+ break;
+ case 'v':
+ rflags |= SCRV;
+ break;
+ case 'f':
+ rflags |= SCRFORCE;
+ break;
+ }
+ }
+
+ if (fd < 0) {
+ fd = scopen(0, oflags, &err);
+ if (fd < 0) {
+ printf("%s\n", scerrtab[err]);
+ return -1;
+ }
+ }
+
+ n = scxreset(fd, rflags, buf, &err);
+ if (n && !(rflags & SCRV)) {
+ printf("atr ");
+ dump_reply(buf, n, 0, 0);
+ }
+ if (err != SCEOK) {
+ printf("%s\n", scerrtab[err]);
+ return -1;
+ }
+
+ return 0;
+}
+
+int dclose(int ac, char *av[])
+{
+ if (fd >= 0) {
+ scclose(fd);
+ fd = -1;
+ }
+ return 0;
+}
+
+int quit(int ac, char *av[])
+{
+ exit(0);
+}
+
+int apdu(int ac, char *av[])
+{
+ int i, n, ins, xcl = cla, p1, p2, p3, r1, r2;
+ unsigned char buf[256], obuf[256], *bp;
+
+ optind = optreset = 1;
+
+ while ((i = getopt(ac, av, "c:")) != -1) {
+ switch (i) {
+ case 'c':
+ sscanf(optarg, "%x", &xcl);
+ break;
+ }
+ }
+
+ if (ac - optind < 4) {
+ printf("usage: apdu [ -c cla ] ins p1 p2 p3 data ...\n");
+ return -1;
+ }
+
+ sscanf(av[optind++], "%x", &ins);
+ sscanf(av[optind++], "%x", &p1);
+ sscanf(av[optind++], "%x", &p2);
+ sscanf(av[optind++], "%x", &p3);
+
+#if 0
+ for (bp = buf, i = optind; i < ac; i++)
+ bp += parse_input(av[i], bp, (int) (sizeof buf - (bp - buf)));
+#else
+ for (bp = buf, i = optind; i < ac; i++) {
+ sscanf(av[i], "%x", &n);
+ *bp++ = n;
+ }
+#endif
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ n = scrw(fd, xcl, ins, p1, p2, p3, buf, sizeof obuf, obuf, &r1, &r2);
+
+ if (n < 0) {
+ printf("scrw failed\n");
+ return -1;
+ }
+
+ dump_reply(obuf, n, r1, r2);
+
+ return 0;
+}
+
+int selfid(int ac, char *av[])
+{
+ unsigned char fid[2];
+
+ if (ac != 2) {
+ printf("usage: f fid\n");
+ return -1;
+ }
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ sectok_parse_fname(av[1], fid);
+ sectok_selectfile(fd, cla, fid, 1);
+
+ return 0;
+}
+
+int class(int ac, char *av[])
+{
+ if (ac > 1)
+ sscanf(av[1], "%x", &cla);
+ else
+ printf("Class %02x\n", cla);
+ return 0;
+}
+
+int dread(int ac, char *av[])
+{
+ int n, p3, fsize, r1, r2;
+ unsigned char buf[CARDIOSIZE];
+
+ if (ac != 2) {
+ printf("usage: read filesize\n");
+ return -1;
+ }
+
+ sscanf(av[1], "%d", &fsize);
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ for (p3 = 0; fsize && p3 < 100000; p3 += n) {
+ n = (fsize < CARDIOSIZE) ? fsize : CARDIOSIZE;
+ if (scread(fd, cla, 0xb0, p3 >> 8, p3 & 0xff, n, buf, &r1, &r2) < 0) {
+ printf("scread failed\n");
+ break;
+ }
+ if (r1 != 0x90 && r1 != 0x61) {
+ print_r1r2(r1, r2);
+ break;
+ }
+ fwrite(buf, 1, n, stdout);
+ fsize -= n;
+ }
+
+ return 0;
+}
+
+int dwrite(int ac, char *av[])
+{
+ int n, p3, r1, r2;
+ FILE *f;
+ unsigned char buf[CARDIOSIZE];
+
+ if (ac != 2) {
+ printf("usage: write input-filename\n");
+ return -1;
+ }
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ f = fopen(av[1], "r");
+ if (!f) {
+ printf("can't open %s\n", av[1]);
+ return -1;
+ }
+
+ n = 0;
+ while ((p3 = fread(buf, 1, CARDIOSIZE, f)) > 0) {
+ if (scwrite(fd, cla, 0xd6, n >> 8, n & 0xff, p3, buf, &r1, &r2) < 0) {
+ printf("scwrite failed\n");
+ break;
+ }
+ if (r1 != 0x90 && r1 != 0x61) {
+ print_r1r2(r1, r2);
+ break;
+ }
+ n += p3;
+ }
+ fclose(f);
+
+ return (n ? 0 : -1);
+}
diff --git a/usr.bin/sectok/cyberflex.c b/usr.bin/sectok/cyberflex.c
new file mode 100644
index 00000000000..9fd9fb45216
--- /dev/null
+++ b/usr.bin/sectok/cyberflex.c
@@ -0,0 +1,771 @@
+/* $Id: cyberflex.c,v 1.1 2001/06/27 19:41:45 rees Exp $ */
+
+/*
+copyright 1999, 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.
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#ifdef __linux
+#include <openssl/des.h>
+#else /* __linux */
+#include <des.h>
+#endif
+#include <sectok.h>
+
+#include "sc.h"
+
+#ifdef __sun
+#define des_set_key(key, schedule) des_key_sched(key, schedule)
+#endif
+
+#define MAX_KEY_FILE_SIZE 1024
+#define NUM_RSA_KEY_ELEMENTS 5
+#define RSA_BIT_LEN 1024
+#define KEY_FILE_HEADER_SIZE 8
+
+static unsigned char key_fid[] = {0x00, 0x11};
+static unsigned char DFLTATR[] = {0x81, 0x10, 0x06, 0x01};
+static unsigned char AUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
+
+/* default signed applet key of Cyberflex Access */
+static des_cblock app_key = {0x6A, 0x21, 0x36, 0xF5, 0xD8, 0x0C, 0x47, 0x83};
+
+char *apptype[] = {
+ "?",
+ "applet",
+ "app",
+ "app/applet",
+};
+
+char *appstat[] = {
+ "?",
+ "created",
+ "installed",
+ "registered",
+};
+
+char *filestruct[] = {
+ "binary",
+ "fixed rec",
+ "variable rec",
+ "cyclic",
+ "program",
+};
+
+int jdefault(int ac, char *av[])
+{
+ unsigned char buf[8];
+ int i, p1 = 4, r1, r2;
+
+ optind = optreset = 1;
+
+ while ((i = getopt(ac, av, "d")) != -1) {
+ switch (i) {
+ case 'd':
+ p1 = 5;
+ break;
+ }
+ }
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ scwrite(fd, cla, 0x08, p1, 0, 0, buf, &r1, &r2);
+ if (r1 != 0x90) {
+ /* error */
+ print_r1r2(r1, r2);
+ return -1;
+ }
+ return 0;
+}
+
+int jatr(int ac, char *av[])
+{
+ unsigned char buf[64];
+ int n = 0, r1, r2;
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ buf[n++] = 0x90;
+ buf[n++] = 0x94; /* TA1 */
+ buf[n++] = 0x40; /* TD1 */
+ buf[n++] = 0x28; /* TC2 (WWT=4sec) */
+ if (ac > optind) {
+ /* set historical bytes from command line */
+ n += parse_input(av[1], &buf[n], 15);
+ } else {
+ /* no historical bytes given, use default */
+ memmove(&buf[n], DFLTATR, sizeof DFLTATR);
+ n += sizeof DFLTATR;
+ }
+ buf[0] |= ((n - 2) & 0xf);
+ scwrite(fd, cla, 0xfa, 0, 0, n, buf, &r1, &r2);
+ if (r1 != 0x90) {
+ /* error */
+ print_r1r2(r1, r2);
+ return -1;
+ }
+ return 0;
+}
+
+int jdata(int ac, char *av[])
+{
+ unsigned char buf[32];
+ int i, r1, r2;
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ scread(fd, cla, 0xca, 0, 1, 0x16, buf, &r1, &r2);
+ if (r1 == 0x90) {
+ printf("serno ");
+ for (i = 0; i < 6; i++)
+ printf("%02x ", buf[i]);
+ printf("batch %02x sver %d.%02d ", buf[6], buf[7], buf[8]);
+ if (buf[9] == 0x0c)
+ printf("augmented ");
+ else if (buf[9] == 0x0b)
+ ;
+ else
+ printf("unknown ");
+ printf("crypto %9.9s class %02x\n", &buf[10], buf[19]);
+ } else {
+ /* error */
+ print_r1r2(r1, r2);
+ }
+ return 0;
+}
+
+#define JDIRSIZE 40
+
+int ls(int ac, char *av[])
+{
+ int p2, f0, f1, r1, r2;
+ char ftype[32], fname[6];
+ unsigned char buf[JDIRSIZE];
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ for (p2 = 0; ; p2++) {
+ if (scread(fd, cla, 0xa8, 0, p2, JDIRSIZE, buf, &r1, &r2) < 0)
+ break;
+ if (r1 != 0x90)
+ break;
+ f0 = buf[4];
+ f1 = buf[5];
+ if (f0 == 0xff || f0 + f1 == 0)
+ continue;
+ sectok_fmt_fid(fname, f0, f1);
+ if (buf[6] == 1)
+ /* root */
+ sprintf(ftype, "root");
+ else if (buf[6] == 2) {
+ /* DF */
+ if (buf[12] == 27)
+ sprintf(ftype, "%s %s", appstat[buf[10]], apptype[buf[9]]);
+ else
+ sprintf(ftype, "directory");
+ } else if (buf[6] == 4)
+ /* EF */
+ sprintf(ftype, "%s", filestruct[buf[13]]);
+ printf("%4s %5d %s\n", fname, (buf[2] << 8) | buf[3], ftype);
+ }
+ return 0;
+}
+
+int jaut(int ac, char *av[])
+{
+ if (fd < 0)
+ reset(0, NULL);
+
+ cla = cyberflex_inq_class(fd);
+ printf("Class %02x\n", cla);
+ return cyberflex_verify_AUT0(fd, cla, AUT0, sizeof AUT0);
+}
+
+#define MAX_BUF_SIZE 256
+#define MAX_APP_SIZE 4096
+#define MAX_APDU_SIZE 0xfa
+#define BLOCK_SIZE 8
+#define MAXTOKENS 16
+
+unsigned char *app_name;
+unsigned char progID[2], contID[2], aid[MAX_BUF_SIZE];
+int cont_size, inst_size;
+int aid_len;
+
+int analyze_load_options(int ac, char *av[])
+{
+ int i, rv;
+
+ progID[0] = 0x77;
+ progID[1] = 0x77;
+ contID[0] = 0x77;
+ contID[1] = 0x78;
+ cont_size = 1152;
+ inst_size = 1024;
+ aid_len = 5;
+
+ for (i = 0 ; i < 16 ; i ++)
+ aid[i] = 0x77;
+
+ /* applet file name */
+ app_name = av[ac - 1];
+
+ optind = optreset = 1;
+
+ /* switch on options */
+ while (1) {
+ rv = getopt (ac, av, "p:c:s:i:a:");
+ if (rv == -1) break;
+ /*printf ("rv=%c, optarg=%s\n", rv, optarg);*/
+ switch (rv) {
+ case 'p':
+ parse_input(optarg, progID, 2);
+ break;
+ case 'c':
+ parse_input(optarg, contID, 2);
+ break;
+ case 's':
+ sscanf(optarg, "%d", &cont_size);
+ break;
+ case 'i':
+ sscanf(optarg, "%d", &inst_size);
+ break;
+ case 'a':
+ aid_len = parse_input(optarg, aid, sizeof aid);
+ /*printf ("aid_len = %d\n", aid_len);*/
+ break;
+ default:
+ printf ("unknown option. command aborted.\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int jload(int ac, char *av[])
+{
+ char progname[5], contname[5];
+ unsigned char app_data[MAX_APP_SIZE],
+ data[MAX_BUF_SIZE];
+ int i, j, fd_app, size, rv, r1, r2;
+ des_cblock tmp;
+ des_key_schedule schedule;
+
+ if (analyze_load_options(ac, av) < 0)
+ return -1;
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ sectok_fmt_fid(progname, progID[0], progID[1]);
+ sectok_fmt_fid(contname, contID[0], contID[1]);
+
+ printf ("applet file \"%s\"\n", app_name);
+ printf ("program ID %s\n", progname);
+ printf ("container ID %s\n", contname);
+ printf ("instance container size %d\n", cont_size);
+ printf ("instance data size %d\n", inst_size);
+ printf ("AID ");
+ for (i = 0 ; i < aid_len ; i ++ )
+ printf ("%02x", (unsigned char)aid[i]);
+ printf ("\n");
+
+ /* open the input file */
+ fd_app = open (app_name, O_RDONLY, NULL);
+ if (fd_app == -1) {
+ fprintf (stderr, "cannot open file \"%s\"\n", app_name);
+ return -1;
+ }
+
+ /* read the input file */
+ size = read (fd_app, app_data, MAX_APP_SIZE);
+ if (size == 0) {
+ fprintf (stderr, "file %s size 0??\n", app_name);
+ return -1;
+ }
+ if (size == -1) {
+ fprintf (stderr, "error reading file %s\n", app_name);
+ return -1;
+ }
+
+ /*printf ("file size %d\n", size);*/
+
+ /* size must be able to be divided by BLOCK_SIZE */
+ if (size % BLOCK_SIZE != 0) {
+ fprintf (stderr, "file (%s) size cannot be divided by BLOCK_SIZE.\n",
+ app_name);
+ return -1;
+ }
+
+ /* compute the signature of the applet */
+ /* initialize the result buffer */
+ for (j = 0; j < BLOCK_SIZE; j++ ) {
+ tmp[j] = 0;
+ }
+
+ /* chain. DES encrypt one block, XOR the cyphertext with the next block,
+ ... continues until the end of the buffer */
+
+ des_set_key (&app_key, schedule);
+
+ for (i = 0; i < size/BLOCK_SIZE; i++) {
+ for (j = 0; j < BLOCK_SIZE; j++ ){
+ tmp[j] = tmp[j] ^ app_data[i*BLOCK_SIZE + j];
+ }
+ des_ecb_encrypt (&tmp, &tmp, schedule, DES_ENCRYPT);
+ }
+
+ /* print out the signature */
+ printf ("signature ");
+ for (j = 0; j < BLOCK_SIZE; j++ ) {
+ printf ("%02x", tmp[j]);
+ }
+ printf ("\n");
+
+ /* select the default loader */
+ rv = scwrite(fd, cla, 0xa4, 0x04, 0, 0, NULL, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("selecting default loader: ");
+ print_r1r2(r1, r2);
+ return -1;
+ }
+
+ /* select 3f.00 (root) */
+ rv = sectok_selectfile(fd, cla, root_fid, 0);
+ if (rv < 0) return rv;
+
+ /* create program file */
+ data[0] = (size + 16) / 256; /* size, upper byte */
+ data[1] = (size + 16) % 256; /* size, lower byte */
+ data[2] = progID[0]; /* FID, upper */
+ data[3] = progID[1]; /* FID, lower */
+ data[4] = 0x03; /* file type = 3 (program file) */
+ data[5] = 0x01; /* status = 1 */
+ data[6] = data[7] = 0x00; /* record related */
+ data[8] = 0xff; /* ACL can do everything with AUT0 */
+ for (i = 9; i < 16; i++ ) {
+ data[i] = 0x00; /* ACL : cannot do anything without AUT0 */
+ }
+
+ rv = scwrite(fd, cla, 0xe0, 0, 0, 0x10, data, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("creating file %s: %s\n", progname, get_r1r2s(r1, r2));
+ return -1;
+ }
+
+ /* select program */
+ rv = sectok_selectfile(fd, cla, progID, 0);
+ if (rv < 0) return rv;
+
+ /* update binary */
+ for (i = 0; i < size; i += MAX_APDU_SIZE) {
+ int send_size;
+
+ /* compute the size to be sent */
+ if (size - i > MAX_APDU_SIZE) send_size = MAX_APDU_SIZE;
+ else send_size = size - i;
+
+ rv = scwrite(fd, cla, 0xd6,
+ i / 256, /* offset, upper byte */
+ i % 256, /* offset, lower byte */
+ send_size,
+ app_data + i, /* program file */
+ &r1, &r2);
+
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("updating binary %s: %s\n", progname, get_r1r2s(r1, r2));
+ return -1;
+ }
+ }
+
+ /* manage program .. validate */
+ rv = scwrite(fd, cla, 0x0a, 01, 0, 0x08,
+ tmp, /* signature */
+ &r1, &r2);
+
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("validating applet in %s: %s\n", progname, get_r1r2s(r1, r2));
+ return -1;
+ }
+
+ /* select the default loader */
+ rv = scwrite(fd, cla, 0xa4, 0x04, 0, 0, NULL, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("selecting default loader: %s\n", get_r1r2s(r1, r2));
+ return -1;
+ }
+
+ /* execute method -- call the install() method in the cardlet.
+ cardlet type 01 (applet, not application)
+ program ID (7777)
+ instance container size (0800 (1152))
+ instance container ID (7778)
+ instance data size (0400 (1024))
+ AID length (0005 (5 byte))
+ AID (7777777777) */
+
+ data[0] = 0x01; /* cardlet type = 1 (applet, not application) */
+ data[1] = progID[0]; /* FID, upper */
+ data[2] = progID[1]; /* FID, lower */
+ data[3] = cont_size / 256; /* instance container size 0x0800 (1152) byte, upper */
+ data[4] = cont_size % 256; /* instance container size 0x0800 (1152) byte, lower */
+ data[5] = contID[0]; /* container ID (7778), upper */
+ data[6] = contID[1]; /* container ID (7778), lower */
+ data[7] = inst_size / 256; /* instance size 0x0400 (1024) byte, upper */
+ data[8] = inst_size % 256; /* instance size 0x0400 (1024) byte, lower */
+ data[9] = 0x00; /* AID length 0x0005, upper */
+ data[10] = aid_len; /* AID length 0x0005, lower */
+ for (i = 0; i < aid_len; i++) data[i + 11] = (unsigned int)aid[i];
+ /* AID (7777777777) */
+
+ rv = scwrite(fd, cla, 0x0c, 0x13, 0, 11 + aid_len, data, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("executing install() method in applet %s: %s\n", progname, get_r1r2s(r1, r2));
+ return -1;
+ }
+
+ /* That's it! :) */
+ return 0;
+}
+
+int junload(int ac, char *av[])
+{
+ char progname[5], contname[5];
+ int r1, r2, rv;
+
+ if (analyze_load_options(ac, av) < 0)
+ return -1;
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ sectok_fmt_fid(progname, progID[0], progID[1]);
+ sectok_fmt_fid(contname, contID[0], contID[1]);
+
+ printf ("program ID %s\n", progname);
+ printf ("container ID %s\n", contname);
+ /*printf ("AID ");
+ for (i = 0 ; i < aid_len ; i ++ ) {
+ printf ("%02x", (unsigned char)aid[i]);
+ }
+ printf ("\n");*/
+
+ /*printf ("unload applet\n");*/
+
+ /* select 3f.00 (root) */
+ rv = sectok_selectfile(fd, cla, root_fid, 0);
+ if (rv < 0) return rv;
+
+ /* select program file */
+ rv = sectok_selectfile(fd, cla, progID, 0);
+ if (rv < 0) {
+ printf ("no program file... proceed to delete data container\n");
+ goto del_container;
+ }
+
+ /* manage program -- reset */
+ rv = scwrite(fd, cla, 0x0a, 02, 0, 0x0, NULL, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("resetting applet: %s\n", get_r1r2s(r1, r2));
+ }
+
+ /* delete program file */
+ cyberflex_delete_file(fd, cla, progID[0], progID[1], 1);
+
+ del_container:
+ /* delete data container */
+ cyberflex_delete_file(fd, cla, contID[0], contID[1], 1);
+
+ return 0;
+}
+
+int jselect(int ac, char *av[])
+{
+ int i, r1, r2, rv;
+ unsigned char data[MAX_BUF_SIZE];
+
+ optind = optreset = 1;
+
+ if (analyze_load_options(ac, av) < 0)
+ return -1;
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ printf ("select applet\n");
+ printf ("AID ");
+ for (i = 0 ; i < aid_len ; i ++ )
+ printf ("%02x", (unsigned char)aid[i]);
+ printf ("\n");
+
+ /* select data container (77.78) */
+ /*rv = sectok_selectfile (fd, cla, root_fid, 0);
+ if (rv < 0) return rv;
+ rv = sectok_selectfile (fd, cla, contID, 0);
+ if (rv < 0) return rv;*/
+
+ /* select the cardlet (7777777777) */
+ for (i = 0; i < aid_len; i++) data[i] = (unsigned char)aid[i];
+ /* quick hack in select_applet()
+ even with F0 card, select applet APDU (00 a4 04)
+ only accepts class byte 00 (not f0) */
+
+ rv = scwrite(fd, cla, 0xa4, 0x04, 0, aid_len, data, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf ("selecting the cardlet: ");
+ for (i = 0 ; i < aid_len ; i ++ ) {
+ printf ("%02x", (unsigned char)aid[i]);
+ }
+ printf ("\n");
+ print_r1r2 (r1, r2);
+ return -1;
+ }
+
+ return 0;
+}
+
+int jdeselect(int ac, char *av[])
+{
+ int r1, r2, rv;
+
+ if (fd < 0)
+ reset(0, NULL);
+
+ rv = scwrite(fd, cla, 0xa4, 0x04, 0, 0x00, NULL, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf ("selecting the default loader: ");
+ print_r1r2 (r1, r2);
+ return -1;
+ }
+
+ return 0;
+}
+
+#define DELIMITER " :\t\n"
+#define KEY_BLOCK_SIZE 14
+
+/* download DES keys into 3f.00/00.11 */
+int cyberflex_load_key (int fd, unsigned char *buf)
+{
+ int r1, r2, rv, argc = 0, i, j, tmp;
+ unsigned char *token;
+ unsigned char data[MAX_BUF_SIZE];
+ unsigned char key[BLOCK_SIZE];
+
+#if 0
+ /* select the default loader */
+ rv = scwrite(fd, cla, 0xa4, 0x04, 0, 0x00, NULL, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ // error
+ printf ("selecting the default loader: ");
+ print_r1r2 (r1, r2);
+ return -1;
+ }
+#endif
+
+ printf ("ca_load_key buf=%s\n", buf);
+ token = strtok (buf, DELIMITER);
+ token = strtok (NULL, DELIMITER);
+ if (token == NULL) {
+ printf ("Usage: jk number_of_keys\n");
+ return -1;
+ }
+ argc = atoi (token);
+
+ if (argc > 2) {
+ printf ("current Cyberflex Access cannot download more than 2 keys to the key file. Sorry. :(\n");
+ return -1;
+ }
+
+ if (argc < 0) {
+ printf ("you want to down load %d keys??\n", argc);
+ return -1;
+ }
+
+ /* Now let's do it. :) */
+
+ /* add the AUT0 */
+ cyberflex_fill_key_block (data, 0, 1, AUT0);
+
+ /* add the applet sign key */
+ cyberflex_fill_key_block (data+KEY_BLOCK_SIZE, 5, 0, app_key);
+
+ /* then add user defined keys */
+ for ( i = 0 ; i < argc ; i++ ) {
+ printf ("key %d : ", i);
+ for ( j = 0 ; j < BLOCK_SIZE ; j++ ) {
+ fscanf (cmdf, "%02x", &tmp);
+ key[j] = (unsigned char)tmp;
+ }
+
+ cyberflex_fill_key_block (data + 28 + i*KEY_BLOCK_SIZE, 6 + i, 0, key);
+ }
+
+ /* add the suffix */
+ data[28 + argc*KEY_BLOCK_SIZE] = 0;
+ data[28 + argc*KEY_BLOCK_SIZE + 1] = 0;
+
+ for ( i = 0 ; i < KEY_BLOCK_SIZE * (argc + 2) + 2; i++ )
+ printf ("%02x ", data[i]);
+ printf ("\n");
+
+ /* select the key file */
+ /* select 3f.00 (root) */
+ rv = sectok_selectfile(fd, cla, root_fid, 0);
+ if (rv < 0) return rv;
+
+ /* select 00.11 (key file) */
+ rv = sectok_selectfile(fd, cla, key_fid, 0);
+ if (rv < 0) return rv;
+
+ /* all righty, now let's send it to the card! :) */
+ rv = scwrite(fd, cla, 0xd6, 0, 0, KEY_BLOCK_SIZE * (argc + 2) + 2,
+ data, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("writing the key file 00.11: ");
+ print_r1r2(r1, r2);
+ return -1;
+ }
+ print_r1r2 (r1, r2);
+
+ return 0;
+}
+
+/* download AUT0 key into 3f.00/00.11 */
+int load_AUT0(int fd, unsigned char *buf)
+{
+ int r1, r2, rv, i, tmp;
+ unsigned char data[MAX_BUF_SIZE];
+ unsigned char key[BLOCK_SIZE];
+
+ printf ("load AUT0\n");
+
+ printf ("ca_load_AUT0 buf=%s\n", buf);
+
+ /* Now let's do it. :) */
+
+ /* get the AUT0 */
+ printf ("input AUT0 : ");
+ for ( i = 0 ; i < BLOCK_SIZE ; i++ ) {
+ fscanf (cmdf, "%02x", &tmp);
+ key[i] = (unsigned char)tmp;
+ }
+ cyberflex_fill_key_block (data, 0, 1, key);
+
+#if 0
+ /* add the suffix */
+ data[KEY_BLOCK_SIZE] = 0;
+ data[KEY_BLOCK_SIZE + 1] = 0;
+#endif
+
+ for ( i = 0 ; i < KEY_BLOCK_SIZE ; i++ )
+ printf ("%02x ", data[i]);
+ printf ("\n");
+
+ /* select the key file */
+ /* select 3f.00 (root) */
+ rv = sectok_selectfile(fd, cla, root_fid, 0);
+ if (rv < 0) return rv;
+
+ /* select 00.11 (key file) */
+ rv = sectok_selectfile(fd, cla, key_fid, 0);
+ if (rv < 0) return rv;
+
+ /* all righty, now let's send it to the card! :) */
+ rv = scwrite(fd, cla, 0xd6, 0, 0, KEY_BLOCK_SIZE,
+ data, &r1, &r2);
+ if (r1 != 0x90 && r1 != 0x61) {
+ /* error */
+ printf("writing the key file 00.11: ");
+ print_r1r2(r1, r2);
+ return -1;
+ }
+ print_r1r2(r1, r2);
+
+ return 0;
+}
+
+/* download RSA private key into 3f.00/00.12 */
+int cyberflex_load_rsa(int fd, unsigned char *buf)
+{
+ int rv, i, j, tmp;
+ static unsigned char key_fid[] = {0x00, 0x12};
+ static char *key_names[NUM_RSA_KEY_ELEMENTS]= {"p", "q", "1/p mod q",
+ "d mod (p-1)", "d mod (q-1)"};
+ unsigned char *key_elements[NUM_RSA_KEY_ELEMENTS];
+
+ printf ("ca_load_rsa_priv buf=%s\n", buf);
+
+ printf ("input 1024 bit RSA CRT key\n");
+ for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++) {
+ printf ("%s (%d bit == %d byte) : ", key_names[i],
+ RSA_BIT_LEN/2, RSA_BIT_LEN/2/8);
+ key_elements[i] = (unsigned char *) malloc(RSA_BIT_LEN/8);
+ for ( j = 0 ; j < RSA_BIT_LEN/8/2 ; j++ ) {
+ fscanf (cmdf, "%02x", &tmp);
+ key_elements[i][j] = (unsigned char)tmp;
+ }
+ }
+
+#ifdef DEBUG
+ printf ("print RSA CRT key\n");
+ for (i = 0 ; i < NUM_RSA_KEY_ELEMENTS ; i ++ ) {
+ printf ("%s : ", key_names[i]);
+ for ( j = 0 ; j < RSA_BIT_LEN/8/2 ; j++ ) {
+ printf ("%02x ", key_elements[i][j]);
+ }
+ }
+#endif
+
+ rv = cyberflex_load_rsa_priv(fd, cla, key_fid, NUM_RSA_KEY_ELEMENTS, RSA_BIT_LEN, key_elements);
+
+ for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
+ free(key_elements[i]);
+ return rv;
+}
diff --git a/usr.bin/sectok/main.c b/usr.bin/sectok/main.c
new file mode 100644
index 00000000000..1e96b5b6bd9
--- /dev/null
+++ b/usr.bin/sectok/main.c
@@ -0,0 +1,133 @@
+/* $Id: main.c,v 1.1 2001/06/27 19:41:45 rees Exp $ */
+
+/*
+ * Smartcard commander.
+ * Written by Jim Rees and others at University of Michigan.
+ */
+
+/*
+copyright 2001
+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.
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <sectok.h>
+
+#include "sc.h"
+
+#define MAXTOKENS 300
+#define CARDIOSIZE 200
+
+const char usage[] =
+"Usage: sectok [-1234hHf:s:]\n"
+" 1 - 4 : specify card reader number\n"
+" f script_file : run commands from the script file\n"
+" s sleep_time : set sleep between commands in the script\n"
+" h : this message\n"
+;
+
+int fd = -1, cla, sleepytime;
+FILE *cmdf;
+
+int
+main(ac, av)
+int ac;
+char *av[];
+{
+ int i, port, tc;
+ char buf[256], *scriptfile = NULL, *tp, *tv[MAXTOKENS];
+
+ while ((i = getopt(ac, av, "1234c:d:f:Hhs:")) != -1) {
+ switch (i) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ port = i - '1';
+ break;
+ case 'f':
+ scriptfile = optarg;
+ break;
+ case 's':
+ sleepytime = atoi(optarg);
+ break;
+ case 'h':
+ case '?':
+ fputs(usage, stdout);
+ exit(0);
+ break;
+ }
+ }
+
+ if (optind != ac) {
+ /* Dispatch from command line */
+ dispatch(ac - optind, &av[optind]);
+ exit(0);
+ }
+
+ if (scriptfile != NULL) {
+ cmdf = fopen(scriptfile, "r");
+ if (cmdf == NULL) {
+ perror(scriptfile);
+ exit(2);
+ }
+ } else
+ cmdf = stdin;
+
+ /* Interactive mode, or script file */
+
+ /* The Main Loop */
+ while (1) {
+ fflush(stdout);
+ if (sleepytime)
+ usleep(sleepytime * 1000);
+ if (cmdf == stdin) {
+ fprintf(stderr, "sectok> ");
+ fflush(stderr);
+ }
+
+ if (!fgets(buf, sizeof buf, cmdf))
+ break;
+ if (cmdf != stdin)
+ printf("sectok> %s", buf);
+
+ for ((tp = strtok(buf, " \t\n\r")), tc = 0; tp; (tp = strtok(NULL, " \t\n\r")), tc++) {
+ if (tc < MAXTOKENS - 1)
+ tv[tc] = tp;
+ }
+ tv[tc] = NULL;
+
+ dispatch(tc, tv);
+ }
+
+ exit(0);
+}
diff --git a/usr.bin/sectok/sc.h b/usr.bin/sectok/sc.h
new file mode 100644
index 00000000000..6cc2e38a5ea
--- /dev/null
+++ b/usr.bin/sectok/sc.h
@@ -0,0 +1,59 @@
+/* $Id: sc.h,v 1.1 2001/06/27 19:41:46 rees Exp $ */
+
+/*
+ * Smartcard commander.
+ * Written by Jim Rees and others at University of Michigan.
+ */
+
+/*
+copyright 2001
+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.
+*/
+
+extern int fd, cla;
+extern FILE *cmdf;
+
+int dispatch(int ac, char *av[]);
+int help(int ac, char *av[]);
+int reset(int ac, char *av[]);
+int dclose(int ac, char *av[]);
+int quit(int ac, char *av[]);
+int apdu(int ac, char *av[]);
+int selfid(int ac, char *av[]);
+int class(int ac, char *av[]);
+int dread(int ac, char *av[]);
+int dwrite(int ac, char *av[]);
+int ls(int ac, char *av[]);
+int jdefault(int ac, char *av[]);
+int jatr(int ac, char *av[]);
+int jdata(int ac, char *av[]);
+int jaut(int ac, char *av[]);
+int jload(int ac, char *av[]);
+int junload(int ac, char *av[]);
+int jselect(int ac, char *av[]);
+int jdeselect(int ac, char *av[]);
diff --git a/usr.bin/sectok/sectok.1 b/usr.bin/sectok/sectok.1
new file mode 100644
index 00000000000..48f41415016
--- /dev/null
+++ b/usr.bin/sectok/sectok.1
@@ -0,0 +1,122 @@
+.\" $OpenBSD: sectok.1,v 1.1 2001/06/27 19:41:46 rees Exp $
+.\"
+.\" copyright 1997, 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.
+
+.Dd January 10, 2001
+.Dt PAY 1
+.Os
+.Sh NAME
+.Nm pay
+.Nd communicate with smartcards using iso7816
+.Sh SYNOPSIS
+.Nm pay
+.Ar [-ht]
+.Sh DESCRIPTION
+.Nm
+is a command-line-like interface for communicating with smartcards. APDU's () can be sent to the card, and results are displayed. Some commands are card-specific, and focus on the Schlumberger Cyberflex Access Javacards, as that is one of CITI's most commonly used cards.
+
+The
+.Nm
+options are as follows:
+
+ -h watch for card removal.
+.Nm
+alerts user of this event
+
+ -t change the ATR timeout of a card. Many cards do not conform to the ISO specs, and use varying lengths of ATR timeouts.
+
+
+The
+.Nm
+commands are as follows:
+
+1/2 - number of port to which smartcard reader is attached also calls reset (and accepts same modifiers) modifers: t -
+
+r - issue a reset to the card
+ modifers: v - verbose
+ f - force open
+ i - return immediately if there is no card in the reader
+
+C - set the instruction class
+
+f - select or open a file
+ options: / - select root file (30 00)
+ <byte>.<byte>
+ <byte> <byte> - select file designated by
+ these two bytes
+
+g - stat currently selected file
+
+?/h - display the help screen
+ option: command you want help on
+
+i/o/b - send an 'in/out/in-out' command
+ requires ins, p1, p2, p3
+ options: c - allows you to specify class byte
+
+T - send T=1 I block and get reply
+ options: S - send R/S block
+
+I - find instructions
+
+j - Cyberflex: Verify AUT0
+ options:
+ r - reset to default loader
+ s - set selected app as default
+ a - fix broken java atr
+ x - list files in selected DF
+ l - download applet (.bin)
+ options -p program FID, -c instance directory FID,
+ -s data directory size, -i data container size,
+ -a applet AID
+ u - unload applet
+ options -p program ID, -c instance directory FID,
+ -a applet AID
+ p - select applet
+ -a applet AID
+ q - select default loader as current
+ k - load DES key (Usage: jk number_of_keys)
+ R - load RSA private key
+
+s - Sm@rt Cafe:
+ l - download applet (.CAP)
+
+R - read file
+ R filesize
+
+W - write file
+ W <filename>
+
+x - explore (similar to unix `ls`)
+
+c - dump file contents
+
+e - eject
+
+q - quit