# HG changeset patch # User Mychaela Falconia # Date 1611448330 0 # Node ID b57cf64ece2982f4679ef03fdcf691837a8f40bf # Parent 1d7d8615d6282e373e4dca9026f17cd24aa555a6 fc-simtool project started diff -r 1d7d8615d628 -r b57cf64ece29 .hgignore --- a/.hgignore Sat Jan 23 17:21:08 2021 +0000 +++ b/.hgignore Sun Jan 24 00:32:10 2021 +0000 @@ -24,3 +24,5 @@ ^lunalcd/ppmtoimg$ ^pcsc-test/pcsc-test[12]$ + +^simtool/fc-simtool$ diff -r 1d7d8615d628 -r b57cf64ece29 simtool/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/Makefile Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,12 @@ +CC= gcc +CFLAGS= -O2 -I/usr/include/PCSC +PROG= fc-simtool +OBJS= apdu.o atr.o cardconnect.o dispatch.o globals.o main.o select.o + +all: ${PROG} + +${PROG}: ${OBJS} + ${CC} ${CFLAGS} -o $@ ${OBJS} -lpcsclite + +clean: + rm -f ${PROG} *.o diff -r 1d7d8615d628 -r b57cf64ece29 simtool/apdu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/apdu.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include "globals.h" + +apdu_exchange(cmd_apdu, cmd_apdu_len) + u_char *cmd_apdu; + unsigned cmd_apdu_len; +{ + LONG rv; + DWORD dwRecvLength; + u_char *sw; + + dwRecvLength = 258; + rv = SCardTransmit(hCard, SCARD_PCI_T0, cmd_apdu, cmd_apdu_len, NULL, + sim_resp_data, &dwRecvLength); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardTransmit: %s\n", + pcsc_stringify_error(rv)); + return(-1); + } + if (dwRecvLength < 2) { + fprintf(stderr, + "error: SCardTransmit response is shorter than 2 SW bytes\n"); + return(-1); + } + sim_resp_data_len = dwRecvLength - 2; + sw = sim_resp_data + sim_resp_data_len; + sim_resp_sw = (sw[0] << 8) | sw[1]; + return(0); +} diff -r 1d7d8615d628 -r b57cf64ece29 simtool/atr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/atr.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include "globals.h" + +#define MAX_ATR_BYTES 33 + +retrieve_atr() +{ + u_char atrbuf[MAX_ATR_BYTES]; + LONG rv; + DWORD dwAttrLen; + unsigned n; + + dwAttrLen = MAX_ATR_BYTES; + rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, atrbuf, &dwAttrLen); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardGetAttrib for ATR: %s\n", + pcsc_stringify_error(rv)); + return(-1); + } + printf("ATR:"); + for (n = 0; n < dwAttrLen; n++) + printf(" %02X", atrbuf[n]); + putchar('\n'); + return(0); +} diff -r 1d7d8615d628 -r b57cf64ece29 simtool/cardconnect.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/cardconnect.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include +#include +#include "globals.h" + +setup_pcsc_context() +{ + LONG rv; + + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardEstablishContext: %s\n", + pcsc_stringify_error(rv)); + exit(1); + } + return(0); +} + +get_reader_name() +{ + LONG rv; + DWORD dwReaders; + + rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardListReaders 1st call: %s\n", + pcsc_stringify_error(rv)); + SCardReleaseContext(hContext); + exit(1); + } + if (dwReaders < 1) { + fprintf(stderr, + "error: dwReaders returned by SCardListReaders() is less than 1\n"); + SCardReleaseContext(hContext); + exit(1); + } + reader_name_buf = malloc(dwReaders); + if (!reader_name_buf) { + perror("malloc for readers list"); + SCardReleaseContext(hContext); + exit(1); + } + reader_name_buf[0] = '\0'; + rv = SCardListReaders(hContext, NULL, reader_name_buf, &dwReaders); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardListReaders 2nd call: %s\n", + pcsc_stringify_error(rv)); + SCardReleaseContext(hContext); + exit(1); + } + if (reader_name_buf[0] == '\0') { + fprintf(stderr, + "error: list returned by SCardListReaders() begins with a NUL byte\n"); + SCardReleaseContext(hContext); + exit(1); + } + if (!memchr(reader_name_buf, 0, dwReaders)) { + fprintf(stderr, +"error: list returned by SCardListReaders() does not contain a NUL byte\n"); + SCardReleaseContext(hContext); + exit(1); + } + return(0); +} + +connect_to_card() +{ + LONG rv; + DWORD dwActiveProtocol; + + rv = SCardConnect(hContext, reader_name_buf, SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardConnect: %s\n", pcsc_stringify_error(rv)); + SCardReleaseContext(hContext); + exit(1); + } + return(0); +} diff -r 1d7d8615d628 -r b57cf64ece29 simtool/dispatch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/dispatch.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,80 @@ +/* + * This module implements the command dispatch for fc-simtool + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "globals.h" + +extern int cmd_select(); + +cmd_exit() +{ + SCardDisconnect(hCard, SCARD_UNPOWER_CARD); + SCardReleaseContext(hContext); + exit(0); +} + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + int (*func)(); +} cmdtab[] = { + {"exit", 0, 0, cmd_exit}, + {"quit", 0, 0, cmd_exit}, + {"select", 1, 1, cmd_select}, + {0, 0, 0, 0} +}; + +simtool_dispatch_cmd(cmd) + char *cmd; +{ + char *argv[10]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = cmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return(0); + argv[0] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + fprintf(stderr, "error: no such command\n"); + return(-1); + } + for (ap = argv + 1; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv - 1 >= tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + if (ap - argv - 1 < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(-1); + } + *ap = 0; + return tp->func(ap - argv, argv); +} diff -r 1d7d8615d628 -r b57cf64ece29 simtool/globals.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/globals.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,9 @@ +#include +#include +#include + +SCARDCONTEXT hContext; +SCARDHANDLE hCard; +char *reader_name_buf; +u_char sim_resp_data[258]; +unsigned sim_resp_data_len, sim_resp_sw; diff -r 1d7d8615d628 -r b57cf64ece29 simtool/globals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/globals.h Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,7 @@ +/* extern definitions for global vars defined in globals.c */ + +extern SCARDCONTEXT hContext; +extern SCARDHANDLE hCard; +extern char *reader_name_buf; +extern u_char sim_resp_data[]; +extern unsigned sim_resp_data_len, sim_resp_sw; diff -r 1d7d8615d628 -r b57cf64ece29 simtool/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/main.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include "globals.h" + +main(argc, argv) + char **argv; +{ + char command[512]; + + setup_pcsc_context(); + get_reader_name(); + printf("Card reader name: %s\n", reader_name_buf); + connect_to_card(); + retrieve_atr(); + for (;;) { + if (isatty(0)) { + fputs("simtool> ", stdout); + fflush(stdout); + } + if (!fgets(command, sizeof command, stdin)) + cmd_exit(); + simtool_dispatch_cmd(command); + } +} diff -r 1d7d8615d628 -r b57cf64ece29 simtool/select.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simtool/select.c Sun Jan 24 00:32:10 2021 +0000 @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "globals.h" + +select_op(file_id) + unsigned file_id; +{ + u_char cmd[7]; + int rc; + unsigned expect_resp_len; + + /* SELECT command APDU */ + cmd[0] = 0xA0; + cmd[1] = 0xA4; + cmd[2] = 0; + cmd[3] = 0; + cmd[4] = 2; + cmd[5] = file_id >> 8; + cmd[6] = file_id; + rc = apdu_exchange(cmd, 7); + if (rc < 0) + return(rc); + if ((sim_resp_sw & 0xFF00) != 0x9F00) { + fprintf(stderr, + "error or unexpected SW response to SELECT of 0x%04X: %04X\n", + file_id, sim_resp_sw); + return(-1); + } + expect_resp_len = sim_resp_sw & 0xFF; + /* GET RESPONSE follow-up */ + cmd[1] = 0xC0; + cmd[4] = expect_resp_len; + rc = apdu_exchange(cmd, 5); + if (rc < 0) + return(rc); + if (sim_resp_sw != 0x9000) { + fprintf(stderr, + "bad SW resp to GET RESPONSE after SELECT: %04X\n", + sim_resp_sw); + return(-1); + } + if (sim_resp_data_len != expect_resp_len) { + fprintf(stderr, + "error: GET RESPONSE after SELECT returned %u bytes, expected %u\n", + sim_resp_data_len, expect_resp_len); + return(-1); + } + return(0); +} + +cmd_select(argc, argv) + char **argv; +{ + unsigned file_id; + + if (isxdigit(argv[1][0]) && isxdigit(argv[1][1]) && + isxdigit(argv[1][2]) && isxdigit(argv[1][3]) && !argv[1][4]) + file_id = strtoul(argv[1], 0, 16); + else { + fprintf(stderr, + "select: only hex file IDs are currently supported\n"); + return(-1); + } + return select_op(file_id); +}