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, ¶m);
205 showfield(printfield->id);
206 #else
207 sectok_parse_atr(fd, STRV, atr, n, ¶m);
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