1 /* $Id: cmds.c,v 1.12 2002/08/15 16:15:12 rees Exp $ */
2 
3 /*
4  * Smartcard commander.
5  * Written by Jim Rees and others at University of Michigan.
6  */
7 
8 /*
9 copyright 2001
10 the regents of the university of michigan
11 all rights reserved
12 
13 permission is granted to use, copy, create derivative works
14 and redistribute this software and such derivative works
15 for any purpose, so long as the name of the university of
16 michigan is not used in any advertising or publicity
17 pertaining to the use or distribution of this software
18 without specific, written prior authorization.  if the
19 above copyright notice or any other identification of the
20 university of michigan is included in any copy of any
21 portion of this software, then the disclaimer below must
22 also be included.
23 
24 this software is provided as is, without representation
25 from the university of michigan as to its fitness for any
26 purpose, and without warranty by the university of
27 michigan of any kind, either express or implied, including
28 without limitation the implied warranties of
29 merchantability and fitness for a particular purpose. the
30 regents of the university of michigan shall not be liable
31 for any damages, including special, indirect, incidental, or
32 consequential damages, with respect to any claim arising
33 out of or in connection with the use of the software, even
34 if it has been or is hereafter advised of the possibility of
35 such damages.
36 */
37 
38 #ifdef __palmos__
39 #pragma pack(2)
40 #include <Common.h>
41 #include <System/SysAll.h>
42 #include <UI/UIAll.h>
43 #include <System/Unix/sys_types.h>
44 #include <System/Unix/unix_stdio.h>
45 #include <System/Unix/unix_stdlib.h>
46 #include <System/Unix/unix_string.h>
47 #include <string.h>
48 #include "getopt.h"
49 #include "sectok.h"
50 #include "field.h"
51 #else
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <signal.h>
56 #include <string.h>
57 #include <sectok.h>
58 #endif
59 
60 #include "sc.h"
61 
62 #define MAXFILELEN 0xffff
63 #define CARDIOSIZE 200
64 
65 struct dispatchtable dispatch_table[] = {
66     /* Non-card commands */
67     { "help", "[command]", help },
68     { "?", "[command]", help },
69     { "reset", "[ -0123ivf ]", reset },
70     { "open", "[ -0123ivf ]", reset },
71     { "close", "", dclose },
72     { "quit", "", quit },
73 
74     /* 7816-4 commands */
75     { "apdu", "[ -c class ] ins p1 p2 p3 data ...", apdu },
76     { "fid", "[ -v ] fid/aid", selfid },
77     { "isearch", "", isearch },
78     { "csearch", "", csearch },
79     { "class", "[ class ]", class },
80     { "read", "[ -x ] [ filesize ]", dread },
81     { "write", "input-filename", dwrite },
82     { "challenge", "[ size ]", challenge },
83     { "pin", "[ -k keyno ] [ PIN ]", vfypin },
84 #ifndef __palmos__
85     { "chpin", "[ -k keyno ]", chpin },
86 #endif
87 
88     /* Cyberflex commands */
89     { "ls", "[ -l ]", ls },
90     { "lsk", "", lsk },
91     { "acl", "[ -x ] fid [ principal: r1 r2 ... ]", acl },
92     { "create", "fid size", jcreate },
93     { "delete", "fid", jdelete },
94     { "jdefault", "[ -d ]", jdefault },
95     { "jatr", "", jatr },
96     { "jdata", "", jdata },
97     { "login", "[ -d ] [ -k keyno ] [ -v ] [ -x hex-aut0 ]", jlogin },
98 #ifndef __palmos__
99     { "jaut", "", jaut },
100     { "jload", "[ -p progID ] [ -c contID ] [ -s cont_size ] [ -i inst_size ] [ -a aid ] [ -v ] filename", jload },
101 #endif
102     { "junload", "[ -p progID ] [ -c contID ]", junload },
103 #ifndef __palmos__
104     { "setpass", "[ -d ] [ -x hex-aut0 ]", jsetpass },
105 #endif
106     { NULL, NULL, NULL }
107 };
108 
109 int curlen;
110 
dispatch(int ac,char * av[])111 int dispatch(int ac, char *av[])
112 {
113     int i;
114 
115     if (ac < 1)
116 	return 0;
117 
118     for (i = 0; dispatch_table[i].cmd; i++) {
119 	if (!strncmp(av[0], dispatch_table[i].cmd, strlen(av[0]))) {
120 	    (dispatch_table[i].action) (ac, av);
121 	    break;
122 	}
123     }
124     if (!dispatch_table[i].cmd) {
125 	printf("unknown command \"%s\"\n", av[0]);
126 	return -1;
127     }
128     return 0;
129 }
130 
help(int ac,char * av[])131 int help(int ac, char *av[])
132 {
133     int i, j;
134 
135     if (ac < 2) {
136 	for (i = 0; dispatch_table[i].cmd; i++)
137 	    printf("%s\n", dispatch_table[i].cmd);
138     } else {
139 	for (j = 1; j < ac; j++) {
140 	    for (i = 0; dispatch_table[i].cmd; i++)
141 		if (!strncmp(av[j], dispatch_table[i].cmd, strlen(av[j])))
142 		    break;
143 	    if (dispatch_table[i].help)
144 		printf("%s %s\n", dispatch_table[i].cmd, dispatch_table[i].help);
145 	    else
146 		printf("no help on \"%s\"\n", av[j]);
147 	}
148     }
149 
150     return 0;
151 }
152 
dump_plain(unsigned char * buf,int n)153 void dump_plain(unsigned char *buf, int n)
154 {
155     int i;
156 
157     for (i = 0; i < n; i++)
158 	printf("%02x ", buf[i]);
159     printf("\n");
160 }
161 
reset(int ac,char * av[])162 int reset(int ac, char *av[])
163 {
164     int i, n, oflags = 0, rflags = 0, vflag = 0, sw;
165     unsigned char atr[34];
166     struct scparam param;
167 
168     optind = optreset = 1;
169 
170     while ((i = getopt(ac, av, "0123ivf")) != -1) {
171 	switch (i) {
172 	case '0':
173 	case '1':
174 	case '2':
175 	case '3':
176 	    port = i - '0';
177 	    break;
178 	case 'i':
179 	    oflags |= STONOWAIT;
180 	    break;
181 	case 'v':
182 	    vflag = 1;
183 	    break;
184 	case 'f':
185 	    rflags |= STRFORCE;
186 	    break;
187 	}
188     }
189 
190     if (fd < 0) {
191 	fd = sectok_open(port, oflags, &sw);
192 	if (fd < 0) {
193 	    sectok_print_sw(sw);
194 	    return -1;
195 	}
196     }
197 
198     aut0_vfyd = 0;
199 
200     n = sectok_reset(fd, rflags, atr, &sw);
201     if (vflag) {
202 #ifdef __palmos__
203 	hidefield(printfield->id);
204 	sectok_parse_atr(fd, STRV, atr, n, &param);
205 	showfield(printfield->id);
206 #else
207 	sectok_parse_atr(fd, STRV, atr, n, &param);
208 #endif
209     }
210     if (!sectok_swOK(sw)) {
211 	printf("sectok_reset: %s\n", sectok_get_sw(sw));
212 	dclose(0, NULL);
213 	return -1;
214     }
215 
216     return 0;
217 }
218 
dclose(int ac,char * av[])219 int dclose(int ac, char *av[])
220 {
221     if (fd >= 0) {
222 	sectok_close(fd);
223 	fd = -1;
224     }
225     return 0;
226 }
227 
quit(int ac,char * av[])228 int quit(int ac, char *av[])
229 {
230     dclose(0, NULL);
231 #ifndef __palmos__
232     exit(0);
233 #else
234     return -1;
235 #endif
236 }
237 
apdu(int ac,char * av[])238 int apdu(int ac, char *av[])
239 {
240     int i, ilen, olen, n, ins, xcl = cla, p1, p2, p3, sw;
241     unsigned char ibuf[256], obuf[256], *bp;
242 
243     optind = optreset = 1;
244 
245     while ((i = getopt(ac, av, "c:")) != -1) {
246 	switch (i) {
247 	case 'c':
248 	    sscanf(optarg, "%x", &xcl);
249 	    break;
250 	}
251     }
252 
253     if (ac - optind < 4) {
254 	printf("usage: apdu [ -c class ] ins p1 p2 p3 data ...\n");
255 	return -1;
256     }
257 
258     sscanf(av[optind++], "%x", &ins);
259     sscanf(av[optind++], "%x", &p1);
260     sscanf(av[optind++], "%x", &p2);
261     sscanf(av[optind++], "%x", &p3);
262 
263     for (bp = ibuf, i = optind, ilen = 0; i < ac; i++) {
264 	sscanf(av[i], "%x", &n);
265 	*bp++ = n;
266 	ilen++;
267     }
268 
269     if (fd < 0 && reset(0, NULL) < 0)
270 	return -1;
271 
272     olen = (p3 && !ilen) ? p3 : sizeof obuf;
273 
274     n = sectok_apdu(fd, xcl, ins, p1, p2, ilen, ibuf, olen, obuf, &sw);
275 
276     sectok_dump_reply(obuf, n, sw);
277 
278     return 0;
279 }
280 
selfid(int ac,char * av[])281 int selfid(int ac, char *av[])
282 {
283     unsigned char fid[16], obuf[256];
284     char *fname;
285     int i, n, sel, fidlen, vflag = 0, sw;
286 
287     optind = optreset = 1;
288 
289     while ((i = getopt(ac, av, "v")) != -1) {
290 	switch (i) {
291 	case 'v':
292 	    vflag = 1;
293 	    break;
294 	}
295     }
296 
297     if (ac - optind == 0) {
298 	/* No fid/aid given; select null aid (default loader for Cyberflex) */
299 	sel = 4;
300 	fidlen = 0;
301     } else {
302 	fname = av[optind++];
303 	if (!strcmp(fname, "..")) {
304 	    /* Special case ".." means parent */
305 	    sel = 3;
306 	    fidlen = 0;
307 	} else if (strlen(fname) < 5) {
308 	    /* fid */
309 	    sel = 0;
310 	    fidlen = 2;
311 	    sectok_parse_fname(fname, fid);
312 	} else {
313 	    /* aid */
314 	    sel = 4;
315 	    fidlen = sectok_parse_input(fname, fid, sizeof fid);
316 	    if (fname[0] == '#') {
317 		/* Prepend 0xfc to the aid to make it a "proprietary aid". */
318 		fid[0] = 0xfc;
319 	    }
320 	}
321     }
322 
323     if (fd < 0 && reset(0, NULL) < 0)
324 	return -1;
325 
326     n = sectok_apdu(fd, cla, 0xa4, sel, 0, fidlen, fid, 256, obuf, &sw);
327     if (!sectok_swOK(sw)) {
328 	printf("Select %02x%02x: %s\n", fid[0], fid[1], sectok_get_sw(sw));
329 	return -1;
330     }
331 
332     if (vflag && !n && sectok_r1(sw) == 0x61 && sectok_r2(sw)) {
333 	/* The card has out data but we must explicitly ask for it */
334 	n = sectok_apdu(fd, cla, 0xc0, 0, 0, 0, NULL, sectok_r2(sw), obuf, &sw);
335     }
336 
337     if (n >= 4) {
338 	/* Some cards put the file length here. No guarantees. */
339 	curlen = (obuf[2] << 8) | obuf[3];
340     }
341 
342     if (vflag)
343 	sectok_dump_reply(obuf, n, sw);
344 
345     return 0;
346 }
347 
isearch(int ac,char * av[])348 int isearch(int ac, char *av[])
349 {
350     int i, r1, sw;
351 
352     if (fd < 0 && reset(0, NULL) < 0)
353 	return -1;
354 
355     /* find instructions */
356     for (i = 0; i < 0xff; i += 2) {
357 	sectok_apdu(fd, cla, i, 0, 0, 0, NULL, 0, NULL, &sw);
358 	r1 = sectok_r1(sw);
359 	if (r1 != 0x06 && r1 != 0x6d && r1 != 0x6e)
360 	    printf("%02x %s %s\n", i, sectok_get_ins(i), sectok_get_sw(sw));
361     }
362     return 0;
363 }
364 
csearch(int ac,char * av[])365 int csearch(int ac, char *av[])
366 {
367     int i, r1, sw;
368 
369     if (fd < 0 && reset(0, NULL) < 0)
370 	return -1;
371 
372     /* find app classes */
373     for (i = 0; i <= 0xff; i++) {
374 	sectok_apdu(fd, i, 0xa4, 0, 0, 2, root_fid, 0, NULL, &sw);
375 	r1 = sectok_r1(sw);
376 	if (r1 != 0x06 && r1 != 0x6d && r1 != 0x6e)
377 	    printf("%02x %s\n", i, sectok_get_sw(sw));
378     }
379     return 0;
380 }
381 
class(int ac,char * av[])382 int class(int ac, char *av[])
383 {
384     if (ac > 1)
385 	sscanf(av[1], "%x", &cla);
386     else
387 	printf("Class %02x\n", cla);
388     return 0;
389 }
390 
dread(int ac,char * av[])391 int dread(int ac, char *av[])
392 {
393     int i, n, col = 0, fsize, xflag = 0, sw;
394     unsigned int p3;
395     unsigned char buf[CARDIOSIZE+1];
396 
397     optind = optreset = 1;
398 
399     while ((i = getopt(ac, av, "x")) != -1) {
400 	switch (i) {
401 	case 'x':
402 	    xflag = 1;
403 	    break;
404 	}
405     }
406 
407     if (ac - optind < 1)
408 	fsize = curlen;
409     else
410 	sscanf(av[optind++], "%d", &fsize);
411 
412     if (!fsize) {
413 	printf("please specify filesize\n");
414 	return -1;
415     }
416 
417     if (fd < 0 && reset(0, NULL) < 0)
418 	return -1;
419 
420     for (p3 = 0; fsize && p3 < MAXFILELEN; p3 += n) {
421 	n = (fsize < CARDIOSIZE) ? fsize : CARDIOSIZE;
422 	n = sectok_apdu(fd, cla, 0xb0, p3 >> 8, p3 & 0xff, 0, NULL, n, buf, &sw);
423 	if (!sectok_swOK(sw)) {
424 	    printf("ReadBinary: %s\n", sectok_get_sw(sw));
425 	    break;
426 	}
427 #ifdef __palmos__
428 	if (xflag) {
429 	    hidefield(printfield->id);
430 	    for (i = 0; i < n; i++) {
431 		printf("%02x ", buf[i]);
432 		if (col++ % 12 == 11)
433 		    printf("\n");
434 	    }
435 	    showfield(printfield->id);
436 	} else {
437 	    buf[n] = '\0';
438 	    printf("%s", buf);
439 	}
440 #else
441 	if (xflag) {
442 	    for (i = 0; i < n; i++) {
443 		printf("%02x ", buf[i]);
444 		if (col++ % 16 == 15)
445 		    printf("\n");
446 	    }
447 	} else
448 	    fwrite(buf, 1, n, stdout);
449 #endif
450 	fsize -= n;
451     }
452 
453     if (xflag && col % 16 != 0)
454 	printf("\n");
455 
456     return 0;
457 }
458 
459 #ifndef __palmos__
dwrite(int ac,char * av[])460 int dwrite(int ac, char *av[])
461 {
462     int n, p3, sw;
463     FILE *f;
464     unsigned char buf[CARDIOSIZE];
465 
466     if (ac != 2) {
467 	printf("usage: write input-filename\n");
468 	return -1;
469     }
470 
471     if (fd < 0 && reset(0, NULL) < 0)
472 	return -1;
473 
474     f = fopen(av[1], "r");
475     if (!f) {
476 	printf("can't open %s\n", av[1]);
477 	return -1;
478     }
479 
480     n = 0;
481     while ((p3 = fread(buf, 1, CARDIOSIZE, f)) > 0) {
482 	sectok_apdu(fd, cla, 0xd6, n >> 8, n & 0xff, p3, buf, 0, NULL, &sw);
483 	if (!sectok_swOK(sw)) {
484 	    printf("UpdateBinary: %s\n", sectok_get_sw(sw));
485 	    break;
486 	}
487 	n += p3;
488     }
489     fclose(f);
490 
491     return (n ? 0 : -1);
492 }
493 #else
dwrite(int ac,char * av[])494 int dwrite(int ac, char *av[])
495 {
496     int n, sw;
497     char *s;
498 
499     if (ac != 2) {
500 	printf("usage: write text\n");
501 	return -1;
502     }
503     s = av[1];
504     n = strlen(s);
505     sectok_apdu(fd, cla, 0xd6, 0, 0, n, s, 0, NULL, &sw);
506     if (!sectok_swOK(sw)) {
507 	printf("UpdateBinary: %s\n", sectok_get_sw(sw));
508 	return -1;
509     }
510     return 0;
511 }
512 #endif
513 
challenge(int ac,char * av[])514 int challenge(int ac, char *av[])
515 {
516     int n = 8, sw;
517     unsigned char buf[256];
518 
519     if (ac > 1)
520 	n = atoi(av[1]);
521 
522     n = sectok_apdu(fd, cla, 0x84, 0, 0, 0, NULL, n, buf, &sw);
523 
524     if (!sectok_swOK(sw)) {
525 	printf("GetChallenge: %s\n", sectok_get_sw(sw));
526 	return -1;
527     }
528 
529     sectok_dump_reply(buf, n, sw);
530     return 0;
531 }
532 
vfypin(int ac,char * av[])533 int vfypin(int ac, char *av[])
534 {
535     int keyno = 1, i, sw;
536     char *pin;
537 
538     optind = optreset = 1;
539 
540     while ((i = getopt(ac, av, "k:")) != -1) {
541 	switch (i) {
542 	case 'k':
543 	    keyno = atoi(optarg);
544 	    break;
545 	}
546     }
547 
548     if (ac - optind >= 1)
549 	pin = av[optind++];
550     else {
551 #ifndef __palmos__
552 	pin = getpass("Enter PIN: ");
553 #else
554 	printf("usage: pin PIN\n");
555 	return -1;
556 #endif
557     }
558 
559     sectok_apdu(fd, cla, 0x20, 0, keyno, strlen(pin), pin, 0, NULL, &sw);
560     bzero(pin, strlen(pin));
561 
562     if (!sectok_swOK(sw)) {
563 	printf("VerifyCHV: %s\n", sectok_get_sw(sw));
564 	return -1;
565     }
566     return 0;
567 }
568 
569 #ifndef __palmos__
chpin(int ac,char * av[])570 int chpin(int ac, char *av[])
571 {
572     int keyno = 1, i, sw;
573     char pin[255];
574 
575     optind = optreset = 1;
576 
577     while ((i = getopt(ac, av, "k:")) != -1) {
578 	switch (i) {
579 	case 'k':
580 	    keyno = atoi(optarg);
581 	    break;
582 	}
583     }
584 
585     strcpy(pin, getpass("Enter Old PIN: "));
586     strcat(pin, getpass("Enter New PIN: "));
587 
588     sectok_apdu(fd, cla, 0x24, 0, keyno, strlen(pin), pin, 0, NULL, &sw);
589     bzero(pin, strlen(pin));
590 
591     if (!sectok_swOK(sw)) {
592 	printf("UpdateCHV: %s\n", sectok_get_sw(sw));
593 	return -1;
594     }
595     return 0;
596 }
597 #endif
598