changeset 85:b57cf64ece29

fc-simtool project started
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 Jan 2021 00:32:10 +0000
parents 1d7d8615d628
children 54c444eb084b
files .hgignore simtool/Makefile simtool/apdu.c simtool/atr.c simtool/cardconnect.c simtool/dispatch.c simtool/globals.c simtool/globals.h simtool/main.c simtool/select.c
diffstat 10 files changed, 354 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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$
--- /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
--- /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 <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/simtool/atr.c	Sun Jan 24 00:32:10 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/simtool/cardconnect.c	Sun Jan 24 00:32:10 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/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 <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pcsclite.h>
+#include <winscard.h>
+#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);
+}
--- /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 <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/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;
--- /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 <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];
+
+	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);
+	}
+}
--- /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 <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;
+	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);
+}