changeset 9:c9ef9e91dd8e

new libcommon, initial version
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Mar 2021 06:55:38 +0000
parents 34bbb0585cab
children ddd767f6e15b
files libcommon/Makefile libcommon/apdu.c libcommon/apducmd.c libcommon/atr.c libcommon/backend.c libcommon/be_init.c libcommon/chkblank.c libcommon/dumpdirfunc.c libcommon/exit.c libcommon/file_id.h libcommon/globalopts.c libcommon/hexdump.c libcommon/localcd.c libcommon/names.c libcommon/simresp.h
diffstat 15 files changed, 696 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/Makefile	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,14 @@
+CC=	gcc
+CFLAGS=	-O2
+OBJS=	apdu.o apducmd.o atr.o backend.o be_init.o chkblank.o dumpdirfunc.o \
+	exit.o globalopts.o hexdump.o localcd.o names.o
+LIB=	libcommon.a
+
+all:	${LIB}
+
+${LIB}:	${OBJS}
+	ar rcu $@ ${OBJS}
+	ranlib $@
+
+clean:
+	rm -f *.[oa] errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/apdu.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,84 @@
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+extern FILE *cpipeF, *rpipeF;
+
+u_char sim_resp_data[258];
+unsigned sim_resp_data_len, sim_resp_sw;
+
+static void
+send_cmd(cmd_apdu, cmd_apdu_len)
+	u_char *cmd_apdu;
+	unsigned cmd_apdu_len;
+{
+	unsigned n;
+
+	for (n = 0; n < cmd_apdu_len; n++)
+		fprintf(cpipeF, "%02X", cmd_apdu[n]);
+	putc('\n', cpipeF);
+	fflush(cpipeF);
+}
+
+static
+parse_response_hex_string(input)
+	char *input;
+{
+	char *cp;
+
+	sim_resp_data_len = 0;
+	for (cp = input; *cp; cp += 2) {
+		if (!isxdigit(cp[0]) || !isxdigit(cp[1])) {
+			fprintf(stderr,
+			"comm error: invalid hex string from back end\n");
+			return(-1);
+		}
+		sim_resp_data[sim_resp_data_len++] =
+			(decode_hex_digit(cp[0]) << 4) |
+			decode_hex_digit(cp[1]);
+	}
+	return(0);
+}
+
+apdu_exchange(cmd_apdu, cmd_apdu_len)
+	u_char *cmd_apdu;
+	unsigned cmd_apdu_len;
+{
+	char inbuf[518], *cp;
+	u_char *sw;
+	int rc;
+
+	send_cmd(cmd_apdu, cmd_apdu_len);
+	if (!fgets(inbuf, sizeof inbuf, rpipeF)) {
+		fprintf(stderr, "comm error: EOF reading from back end\n");
+		return(-1);
+	}
+	cp = index(inbuf, '\n');
+	if (!cp) {
+		fprintf(stderr,
+			"comm error: response from back end has no newline\n");
+		return(-1);
+	}
+	*cp = '\0';
+	if (!inbuf[0]) {
+		fprintf(stderr,
+		"comm error: response from back end is an empty line\n");
+		return(-1);
+	}
+	if (!isxdigit(inbuf[0]) || !isxdigit(inbuf[1]) || !isxdigit(inbuf[2])
+	    || !isxdigit(inbuf[3])) {
+		/* we got a back end error message */
+		fprintf(stderr, "%s\n", inbuf);
+		return(-1);
+	}
+	rc = parse_response_hex_string(inbuf);
+	if (rc < 0)
+		return(rc);
+	sim_resp_data_len -= 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/libcommon/apducmd.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,26 @@
+/*
+ * This module implements a low-level debug command
+ * for users to manually send arbitrary APDUs.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "simresp.h"
+
+cmd_apdu(argc, argv)
+	char **argv;
+{
+	u_char cmd[260];
+	int rc;
+	unsigned len;
+
+	rc = decode_hex_data_from_string(argv[1], cmd, 5, 260);
+	if (rc < 0)
+		return(rc);
+	len = rc;
+	rc = apdu_exchange(cmd, len);
+	if (rc < 0)
+		return(rc);
+	printf("%04X\n", sim_resp_sw);
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/atr.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+extern FILE *cpipeF, *rpipeF;
+extern char be_atr_string[];
+
+cmd_atr()
+{
+	char inbuf[128], *cp;
+
+	/* do we have it already? */
+	if (be_atr_string[0]) {
+		printf("ATR: %s\n", be_atr_string);
+		return(0);
+	}
+	/* nope - request it from the BE */
+	fputs("atr\n", cpipeF);
+	fflush(cpipeF);
+	/* collect BE response */
+	if (!fgets(inbuf, sizeof inbuf, rpipeF)) {
+		fprintf(stderr, "comm error: EOF reading from back end\n");
+		return(-1);
+	}
+	cp = index(inbuf, '\n');
+	if (!cp) {
+		fprintf(stderr,
+			"comm error: response from back end has no newline\n");
+		return(-1);
+	}
+	*cp = '\0';
+	if (!inbuf[0]) {
+		fprintf(stderr,
+		"comm error: response from back end is an empty line\n");
+		return(-1);
+	}
+	puts(inbuf);
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/backend.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,82 @@
+/*
+ * This module is responsible for launching and connecting
+ * our SIM card communication back end.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern unsigned calypso_fd, pcsc_reader_num;
+
+static char calypso_be_pathname[] = "/opt/freecalypso/bin/fcsim-calypso-be";
+static char pcsc_be_pathname[] = "/opt/freecalypso/bin/fc-pcsc-backend";
+
+static char *backend_prog, *backend_argv[3], backend_optarg[16];
+
+FILE *cpipeF, *rpipeF;
+
+static void
+setup_be_calypso()
+{
+	backend_prog = calypso_be_pathname;
+	backend_argv[0] = "fcsim-calypso-be";
+	sprintf(backend_optarg, "-C%u", calypso_fd);
+	backend_argv[1] = backend_optarg;
+	backend_argv[2] = 0;
+}
+
+static void
+setup_be_pcsc()
+{
+	backend_prog = pcsc_be_pathname;
+	backend_argv[0] = "fc-pcsc-backend";
+	sprintf(backend_optarg, "-p%u", pcsc_reader_num);
+	backend_argv[1] = backend_optarg;
+	backend_argv[2] = 0;
+}
+
+launch_backend()
+{
+	int cpipe[2], rpipe[2], rc;
+
+	if (calypso_fd)
+		setup_be_calypso();
+	else
+		setup_be_pcsc();
+	if (pipe(cpipe) < 0 || pipe(rpipe) < 0) {
+		perror("pipe");
+		exit(1);
+	}
+	rc = vfork();
+	if (rc < 0) {
+		perror("vfork for launching back end");
+		exit(1);
+	}
+	if (!rc) {
+		/* we are in the child - prepare to exec the BE */
+		dup2(cpipe[0], 0);
+		dup2(rpipe[1], 1);
+		close(cpipe[0]);
+		close(cpipe[1]);
+		close(rpipe[0]);
+		close(rpipe[1]);
+		/* do the exec */
+		execv(backend_prog, backend_argv);
+		perror(backend_prog);
+		_exit(1);
+	}
+	close(cpipe[0]);
+	close(rpipe[1]);
+	cpipeF = fdopen(cpipe[1], "w");
+	if (!cpipeF) {
+		perror("fdopen");
+		exit(1);
+	}
+	rpipeF = fdopen(rpipe[0], "r");
+	if (!rpipeF) {
+		perror("fdopen");
+		exit(1);
+	}
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/be_init.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,59 @@
+/*
+ * This module is responsible for collecting the initial info
+ * strings emitted by the back end.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+extern FILE *rpipeF;
+
+#define	MAX_INIT_STRING	254
+
+char be_reader_name[MAX_INIT_STRING+1];
+char be_atr_string[MAX_INIT_STRING+1];
+
+static void
+copy_without_leading_space(input_str, dest)
+	char *input_str, *dest;
+{
+	char *cp;
+
+	for (cp = input_str; isspace(*cp); cp++)
+		;
+	strcpy(dest, cp);
+}
+
+collect_backend_init_strings()
+{
+	char inbuf[MAX_INIT_STRING+2], *cp;
+
+	for (;;) {
+		if (!fgets(inbuf, sizeof inbuf, rpipeF)) {
+			fprintf(stderr,
+		"start-up error: EOF reading init strings from back end\n");
+			exit(1);
+		}
+		cp = index(inbuf, '\n');
+		if (!cp) {
+			fprintf(stderr,
+		"start-up error: init string from back end has no newline\n");
+			exit(1);
+		}
+		*cp = '\0';
+		if (!inbuf[0])
+			break;
+		switch (inbuf[0]) {
+		case 'A':
+			copy_without_leading_space(inbuf + 1, be_atr_string);
+			break;
+		case 'R':
+			copy_without_leading_space(inbuf + 1, be_reader_name);
+			break;
+		}
+	}
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/chkblank.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+#include "simresp.h"
+
+check_simresp_all_blank()
+{
+	u_char *dp, *endp;
+
+	dp = sim_resp_data;
+	endp = sim_resp_data + sim_resp_data_len;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(0);
+	return(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/dumpdirfunc.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,107 @@
+/*
+ * This module implements the common function for dumping EF_DIR.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "simresp.h"
+
+static void
+dump_aid(tlv, outf)
+	u_char *tlv;
+	FILE *outf;
+{
+	unsigned reclen, n;
+
+	reclen = tlv[1];
+	fputs(" AID:", outf);
+	for (n = 0; n < reclen; n++)
+		fprintf(outf, " %02X", tlv[n+2]);
+	putc('\n', outf);
+}
+
+static void
+dump_label(tlv, outf)
+	u_char *tlv;
+	FILE *outf;
+{
+	int rc;
+	unsigned textlen;
+
+	fputs(" Label: ", outf);
+	rc = validate_alpha_field(tlv + 2, tlv[1], &textlen);
+	if (rc < 0) {
+		fputs("malformed\n", outf);
+		return;
+	}
+	print_alpha_field(tlv + 2, textlen, outf);
+	putc('\n', outf);
+}
+
+static void
+dump_unknown_tlv(tlv, outf)
+	u_char *tlv;
+	FILE *outf;
+{
+	unsigned reclen, n;
+
+	reclen = tlv[1] + 2;
+	fputs(" TLV:", outf);
+	for (n = 0; n < reclen; n++)
+		fprintf(outf, " %02X", tlv[n]);
+	putc('\n', outf);
+}
+
+void
+dump_efdir_record(outf)
+	FILE *outf;
+{
+	unsigned totlen, reclen;
+	u_char *dp, *endp;
+
+	if (sim_resp_data[0] != 0x61) {
+		fprintf(outf, " bad: first byte != 0x61\n");
+		return;
+	}
+	totlen = sim_resp_data[1];
+	if (totlen < 3 || totlen > 0x7F) {
+		fprintf(outf, " bad: global length byte 0x%02X is invalid\n",
+			totlen);
+		return;
+	}
+	if (totlen + 2 > sim_resp_data_len) {
+		fprintf(outf,
+			" bad: TLV global length exceeds EF record length\n");
+		return;
+	}
+	dp = sim_resp_data + 2;
+	endp = sim_resp_data + 2 + totlen;
+	while (dp < endp) {
+		if (endp - dp < 2) {
+trunc_error:		fprintf(outf, " bad: truncated TLV record\n");
+			return;
+		}
+		if ((dp[0] & 0x1F) == 0x1F) {
+			fprintf(outf, " bad: extended tag not supported\n");
+			return;
+		}
+		if (dp[1] & 0x80) {
+			fprintf(outf, " bad: extended length not supported\n");
+			return;
+		}
+		reclen = dp[1] + 2;
+		if (endp - dp < reclen)
+			goto trunc_error;
+		switch (dp[0]) {
+		case 0x4F:
+			dump_aid(dp, outf);
+			break;
+		case 0x50:
+			dump_label(dp, outf);
+			break;
+		default:
+			dump_unknown_tlv(dp, outf);
+		}
+		dp += reclen;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/exit.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+extern unsigned calypso_fd;
+extern FILE *cpipeF;
+
+good_exit()
+{
+	if (calypso_fd) {
+		fputs("poweroff\n", cpipeF);
+		fflush(cpipeF);
+	}
+	exit(0);
+}
+
+cmd_exit(argc, argv)
+	char **argv;
+{
+	if (argc < 2)
+		good_exit();
+	if (!calypso_fd) {
+		fprintf(stderr,
+	"error: exit arguments are only meaningful with Calypso back end\n");
+		return(-1);
+	}
+	if (!strcmp(argv[1], "bare"))
+		exit(0);
+	if (!strcmp(argv[1], "iota-off")) {
+		fputs("poweroff\n", cpipeF);
+		fflush(cpipeF);
+		exit(0);
+	}
+	fprintf(stderr, "error: \"%s\" is not an understood exit mode\n",
+		argv[1]);
+	return(-1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/file_id.h	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,55 @@
+/* definitions of a few file IDs we find interesting */
+
+#define	FILEID_MF	0x3F00
+#define	FILEID_ADF	0x7FFF
+
+#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
+#define	EF_MBDN		0x6FC7
+#define	EF_MBI		0x6FC9
+#define	EF_MWIS		0x6FCA
+
+/* 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/libcommon/globalopts.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,32 @@
+/*
+ * This module implements parsing of global command line options.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+unsigned calypso_fd, pcsc_reader_num;
+
+parse_global_options(argc, argv)
+	char **argv;
+{
+	extern char *optarg;
+	int c;
+
+	while ((c = getopt(argc, argv, "+C:p:")) != EOF) {
+		switch (c) {
+		case 'C':
+			calypso_fd = atoi(optarg);
+			continue;
+		case 'p':
+			pcsc_reader_num = atoi(optarg);
+			continue;
+		case '?':
+		default:
+			/* error msg already printed */
+			exit(1);
+		}
+	}
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/hexdump.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,44 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include "simresp.h"
+
+display_sim_resp_in_hex(outf)
+	FILE *outf;
+{
+	unsigned off, cc, n, c;
+
+	for (off = 0; off < sim_resp_data_len; off += cc) {
+		fprintf(outf, "%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)
+				putc(' ', outf);
+			putc(' ', outf);
+			if (n < cc)
+				fprintf(outf, "%02X", sim_resp_data[off + n]);
+			else {
+				putc(' ', outf);
+				putc(' ', outf);
+			}
+		}
+		putc(' ', outf);
+		putc(' ', outf);
+		for (n = 0; n < cc; n++) {
+			c = sim_resp_data[off + n];
+			if (c < 0x20 || c > 0x7E)
+				c = '.';
+			putc(c, outf);
+		}
+		putc('\n', outf);
+	}
+	return(0);
+}
+
+cmd_sim_resp(argc, argv, outf)
+	char **argv;
+	FILE *outf;
+{
+	return display_sim_resp_in_hex(outf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/localcd.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,18 @@
+/*
+ * This module implements the local cd command.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+cmd_cd(argc, argv)
+	char **argv;
+{
+	int rc;
+
+	rc = chdir(argv[1]);
+	if (rc < 0)
+		perror(argv[1]);
+	return rc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/names.c	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,79 @@
+/*
+ * 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},
+	{"EF_MBDN",	EF_MBDN},
+	{"EF_MBI",	EF_MBI},
+	{"EF_MWIS",	EF_MWIS},
+	/* 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/libcommon/simresp.h	Sun Mar 14 06:55:38 2021 +0000
@@ -0,0 +1,4 @@
+/* extern definitions for SIM response global vars defined in apdu.c */
+
+extern u_char sim_resp_data[];
+extern unsigned sim_resp_data_len, sim_resp_sw;