# HG changeset patch # User Mychaela Falconia # Date 1612397292 0 # Node ID f691a19f191d0b4d44912cb891136419ab32f043 # Parent 2adb802b2a98d9c8fc01d8401389946b22d5efce fc-uicc-tool skeleton started diff -r 2adb802b2a98 -r f691a19f191d .hgignore --- a/.hgignore Tue Feb 02 17:12:17 2021 +0000 +++ b/.hgignore Thu Feb 04 00:08:12 2021 +0000 @@ -26,3 +26,5 @@ ^pcsc-test/pcsc-test[12]$ ^simtool/fc-simtool$ + +^uicc/fc-uicc-tool$ diff -r 2adb802b2a98 -r f691a19f191d uicc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/Makefile Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,13 @@ +CC= gcc +CFLAGS= -O2 -I/usr/include/PCSC +PROG= fc-uicc-tool +OBJS= apdu.o atr.o cardconnect.o dispatch.o exit.o globals.o hexdump.o main.o\ + names.o script.o select.o + +all: ${PROG} + +${PROG}: ${OBJS} + ${CC} ${CFLAGS} -o $@ ${OBJS} -lpcsclite + +clean: + rm -f ${PROG} *.o diff -r 2adb802b2a98 -r f691a19f191d uicc/apdu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/apdu.c Thu Feb 04 00:08:12 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 2adb802b2a98 -r f691a19f191d uicc/atr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/atr.c Thu Feb 04 00:08:12 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 2adb802b2a98 -r f691a19f191d uicc/cardconnect.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/cardconnect.c Thu Feb 04 00:08:12 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 2adb802b2a98 -r f691a19f191d uicc/dispatch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/dispatch.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,119 @@ +/* + * This module implements the command dispatch for fc-uicc-tool + */ + +#include +#include +#include +#include +#include + +extern int cmd_exec(); +extern int cmd_select(); + +extern int display_sim_resp_in_hex(); +extern int good_exit(); + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + int (*func)(); +} cmdtab[] = { + {"exec", 1, 1, cmd_exec}, + {"exit", 0, 0, good_exit}, + {"quit", 0, 0, good_exit}, + {"select", 1, 1, cmd_select}, + {"sim-resp", 0, 0, display_sim_resp_in_hex}, + {0, 0, 0, 0} +}; + +simtool_dispatch_cmd(cmd, is_script) + char *cmd; +{ + char *argv[10]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = cmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return(0); + if (is_script) + printf("Script command: %s\n", cp); + 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); + } + if (*cp == '"') { + *ap++ = ++cp; + for (;;) { + if (!*cp) { +unterm_qstring: fprintf(stderr, + "error: unterminated quoted string\n"); + return(-1); + } + if (*cp == '"') + break; + if (*cp++ == '\\') { + if (!*cp) + goto unterm_qstring; + cp++; + } + } + *cp++ = '\0'; + } else { + *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); +} + +dispatch_ready_argv(argc, argv) + char **argv; +{ + struct cmdtab *tp; + + 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); + } + if (argc - 1 > tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + if (argc - 1 < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(-1); + } + return tp->func(argc, argv); +} diff -r 2adb802b2a98 -r f691a19f191d uicc/exit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/exit.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include +#include "globals.h" + +good_exit() +{ + SCardDisconnect(hCard, SCARD_UNPOWER_CARD); + SCardReleaseContext(hContext); + exit(0); +} + +error_exit() +{ + SCardDisconnect(hCard, SCARD_UNPOWER_CARD); + SCardReleaseContext(hContext); + exit(1); +} diff -r 2adb802b2a98 -r f691a19f191d uicc/file_id.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/file_id.h Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,51 @@ +/* definitions of a few file IDs we find interesting */ + +#define FILEID_MF 0x3F00 + +#define DF_TELECOM 0x7F10 +#define DF_GSM 0x7F20 +#define DF_DCS1800 0x7F21 + +/* EFs under MF */ +#define EF_DIR 0x2F00 +#define EF_ICCID 0x2FE2 + +/* EFs under DF_GSM */ +#define EF_LP 0x6F05 +#define EF_IMSI 0x6F07 +#define EF_Kc 0x6F20 +#define EF_PLMNsel 0x6F30 +#define EF_HPLMN 0x6F31 +#define EF_ACMmax 0x6F37 +#define EF_SST 0x6F38 +#define EF_ACM 0x6F39 +#define EF_GID1 0x6F3E +#define EF_GID2 0x6F3F +#define EF_PUCT 0x6F41 +#define EF_CBMI 0x6F45 +#define EF_SPN 0x6F46 +#define EF_CBMID 0x6F48 +#define EF_CBMIR 0x6F50 +#define EF_BCCH 0x6F74 +#define EF_ACC 0x6F78 +#define EF_FPLMN 0x6F7B +#define EF_LOCI 0x6F7E +#define EF_AD 0x6FAD +#define EF_PHASE 0x6FAE +#define EF_ECC 0x6FB7 +#define EF_PNN 0x6FC5 +#define EF_OPL 0x6FC6 + +/* EFs under DF_TELECOM */ +#define EF_ADN 0x6F3A +#define EF_FDN 0x6F3B +#define EF_SMS 0x6F3C +#define EF_CCP 0x6F3D +#define EF_MSISDN 0x6F40 +#define EF_SMSP 0x6F42 +#define EF_SMSS 0x6F43 +#define EF_LND 0x6F44 +#define EF_SDN 0x6F49 +#define EF_EXT1 0x6F4A +#define EF_EXT2 0x6F4B +#define EF_EXT3 0x6F4C diff -r 2adb802b2a98 -r f691a19f191d uicc/globals.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/globals.c Thu Feb 04 00:08:12 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 2adb802b2a98 -r f691a19f191d uicc/globals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/globals.h Thu Feb 04 00:08:12 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 2adb802b2a98 -r f691a19f191d uicc/hexdump.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/hexdump.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include "globals.h" + +display_sim_resp_in_hex() +{ + unsigned off, cc, n, c; + + for (off = 0; off < sim_resp_data_len; off += cc) { + printf("%02X:", off); + cc = 16; + if (sim_resp_data_len - off < cc) + cc = sim_resp_data_len - off; + for (n = 0; n < 16; n++) { + if (n == 0 || n == 8) + putchar(' '); + putchar(' '); + if (n < cc) + printf("%02X", sim_resp_data[off + n]); + else { + putchar(' '); + putchar(' '); + } + } + putchar(' '); + putchar(' '); + for (n = 0; n < cc; n++) { + c = sim_resp_data[off + n]; + if (c < 0x20 || c > 0x7E) + c = '.'; + putchar(c); + } + putchar('\n'); + } + return(0); +} diff -r 2adb802b2a98 -r f691a19f191d uicc/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/main.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include "globals.h" + +main(argc, argv) + char **argv; +{ + char command[512]; + int rc; + + setup_pcsc_context(); + get_reader_name(); + printf("Card reader name: %s\n", reader_name_buf); + connect_to_card(); + retrieve_atr(); + if (argc >= 2) { + rc = dispatch_ready_argv(argc - 1, argv + 1); + if (rc) + error_exit(); + else + good_exit(); + } + for (;;) { + if (isatty(0)) { + fputs("uicc> ", stdout); + fflush(stdout); + } + if (!fgets(command, sizeof command, stdin)) + good_exit(); + simtool_dispatch_cmd(command, 0); + } +} diff -r 2adb802b2a98 -r f691a19f191d uicc/names.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/names.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,76 @@ +/* + * This module contains the table of user-friendly file names + * and a function for searching this table. + */ + +#include +#include +#include +#include +#include "file_id.h" + +static struct nametab { + char *name; + int file_id; +} name_table[] = { + {"MF", FILEID_MF}, + {"DF_GSM", DF_GSM}, + {"DF_DCS1800", DF_DCS1800}, + {"DF_TELECOM", DF_TELECOM}, + {"gsm", DF_GSM}, + {"telecom", DF_TELECOM}, + /* EFs under MF */ + {"EF_DIR", EF_DIR}, + {"EF_ICCID", EF_ICCID}, + /* EFs under DF_GSM */ + {"EF_LP", EF_LP}, + {"EF_IMSI", EF_IMSI}, + {"EF_Kc", EF_Kc}, + {"EF_PLMNsel", EF_PLMNsel}, + {"EF_HPLMN", EF_HPLMN}, + {"EF_ACMmax", EF_ACMmax}, + {"EF_SST", EF_SST}, + {"EF_ACM", EF_ACM}, + {"EF_GID1", EF_GID1}, + {"EF_GID2", EF_GID2}, + {"EF_PUCT", EF_PUCT}, + {"EF_CBMI", EF_CBMI}, + {"EF_SPN", EF_SPN}, + {"EF_CBMID", EF_CBMID}, + {"EF_CBMIR", EF_CBMIR}, + {"EF_BCCH", EF_BCCH}, + {"EF_ACC", EF_ACC}, + {"EF_FPLMN", EF_FPLMN}, + {"EF_LOCI", EF_LOCI}, + {"EF_AD", EF_AD}, + {"EF_PHASE", EF_PHASE}, + {"EF_ECC", EF_ECC}, + {"EF_PNN", EF_PNN}, + {"EF_OPL", EF_OPL}, + /* EFs under DF_TELECOM */ + {"EF_ADN", EF_ADN}, + {"EF_FDN", EF_FDN}, + {"EF_SMS", EF_SMS}, + {"EF_CCP", EF_CCP}, + {"EF_MSISDN", EF_MSISDN}, + {"EF_SMSP", EF_SMSP}, + {"EF_SMSS", EF_SMSS}, + {"EF_LND", EF_LND}, + {"EF_SDN", EF_SDN}, + {"EF_EXT1", EF_EXT1}, + {"EF_EXT2", EF_EXT2}, + {"EF_EXT3", EF_EXT3}, + /* table search terminator */ + {0, -1} +}; + +find_symbolic_file_name(soughtname) + char *soughtname; +{ + struct nametab *tp; + + for (tp = name_table; tp->name; tp++) + if (!strcmp(tp->name, soughtname)) + break; + return tp->file_id; +} diff -r 2adb802b2a98 -r f691a19f191d uicc/script.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/script.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,37 @@ +/* + * This module implements the exec command, which is our scripting facility. + */ + +#include +#include +#include +#include + +cmd_exec(argc, argv) + char **argv; +{ + FILE *f; + char linebuf[512], *cp; + int lineno, retval = 0; + + f = fopen(argv[1], "r"); + if (!f) { + perror(argv[1]); + return(-1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: missing newline\n", + argv[1], lineno); + fclose(f); + return(-1); + } + *cp = '\0'; + retval = simtool_dispatch_cmd(linebuf, 1); + if (retval) + break; + } + fclose(f); + return(retval); +} diff -r 2adb802b2a98 -r f691a19f191d uicc/select.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uicc/select.c Thu Feb 04 00:08:12 2021 +0000 @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "globals.h" + +select_op(file_id) + unsigned file_id; +{ + u_char cmd[7]; + int rc; + + /* SELECT command APDU */ + cmd[0] = 0x00; + cmd[1] = 0xA4; + cmd[2] = 0x00; + cmd[3] = 0x04; + cmd[4] = 2; + cmd[5] = file_id >> 8; + cmd[6] = file_id; + rc = apdu_exchange(cmd, 7); + if (rc < 0) + return(rc); + printf("SW response to SELECT: %04X\n", sim_resp_sw); + return(0); +} + +cmd_select(argc, argv) + char **argv; +{ + int 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 + file_id = find_symbolic_file_name(argv[1]); + if (file_id < 0) { + fprintf(stderr, +"error: file ID argument is not a hex value or a recognized symbolic name\n"); + return(-1); + } + return select_op(file_id); +}