changeset 130:f691a19f191d

fc-uicc-tool skeleton started
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 04 Feb 2021 00:08:12 +0000
parents 2adb802b2a98
children d0929cb42e1c
files .hgignore uicc/Makefile uicc/apdu.c uicc/atr.c uicc/cardconnect.c uicc/dispatch.c uicc/exit.c uicc/file_id.h uicc/globals.c uicc/globals.h uicc/hexdump.c uicc/main.c uicc/names.c uicc/script.c uicc/select.c
diffstat 15 files changed, 602 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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$
--- /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
--- /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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+}
--- /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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#include <reader.h>
+#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);
+}
--- /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 <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+}
--- /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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+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);
+}
--- /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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+}
--- /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
--- /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 <sys/types.h>
+#include <pcsclite.h>
+#include <winscard.h>
+
+SCARDCONTEXT hContext;
+SCARDHANDLE hCard;
+char *reader_name_buf;
+u_char sim_resp_data[258];
+unsigned sim_resp_data_len, sim_resp_sw;
--- /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;
--- /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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+}
--- /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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+	}
+}
--- /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 <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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;
+}
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+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);
+}
--- /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 <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+}