changeset 103:90eff13a72fd

fc-simtool: implemented alpha field decoding and spn command
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 25 Jan 2021 04:54:47 +0000
parents 29cc5612797a
children a60645b75a57
files simtool/Makefile simtool/alpha_decode.c simtool/alpha_valid.c simtool/dispatch.c simtool/hlread.c
diffstat 5 files changed, 321 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/simtool/Makefile	Mon Jan 25 02:16:16 2021 +0000
+++ b/simtool/Makefile	Mon Jan 25 04:54:47 2021 +0000
@@ -1,9 +1,9 @@
 CC=	gcc
 CFLAGS=	-O2 -I/usr/include/PCSC
 PROG=	fc-simtool
-OBJS=	apdu.o atr.o cardconnect.o dispatch.o globals.o hexdump.o hexread.o \
-	hlread.o main.o names.o readcmd.o readops.o saverestore.o select.o \
-	telsum.o writecmd.o writeops.o
+OBJS=	alpha_decode.o alpha_valid.o apdu.o atr.o cardconnect.o dispatch.o \
+	globals.o hexdump.o hexread.o hlread.o main.o names.o readcmd.o \
+	readops.o saverestore.o select.o telsum.o writecmd.o writeops.o
 
 all:	${PROG}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simtool/alpha_decode.c	Mon Jan 25 04:54:47 2021 +0000
@@ -0,0 +1,132 @@
+/*
+ * This module contains functions for decoding and displaying alpha fields
+ * that exist in various SIM files.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static char gsm7_decode_table[128] = {
+	'@', 0,   '$',  0,   0,   0,    0,   0,
+	0,   0,   '\n', 0,   0,   '\r', 0,   0,
+	0,   '_', 0,    0,   0,   0,    0,   0,
+	0,   0,   0,    0,   0,   0,    0,   0,
+	' ', '!', '"',  '#', 0,   '%',  '&', 0x27,
+	'(', ')', '*',  '+', ',', '-',  '.', '/',
+	'0', '1', '2',  '3', '4', '5',  '6', '7',
+	'8', '9', ':',  ';', '<', '=',  '>', '?',
+	0,   'A', 'B',  'C', 'D', 'E',  'F', 'G',
+	'H', 'I', 'J',  'K', 'L', 'M',  'N', 'O',
+	'P', 'Q', 'R',  'S', 'T', 'U',  'V', 'W',
+	'X', 'Y', 'Z',  0,   0,   0,    0,   0,
+	0,   'a', 'b',  'c', 'd', 'e',  'f', 'g',
+	'h', 'i', 'j',  'k', 'l', 'm',  'n', 'o',
+	'p', 'q', 'r',  's', 't', 'u',  'v', 'w',
+	'x', 'y', 'z',  0,   0,   0,    0,   0
+};
+
+static char gsm7ext_decode_table[128] = {
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, '^', 0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, '{', '}', 0, 0, 0,   0,   0,   '\\',
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, '[', '~', ']', 0,
+	'|', 0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0,
+	0,   0, 0, 0, 0,   0, 0, 0, 0,   0,   0, 0, 0,   0,   0,   0
+};
+
+static
+is_gsm7_string_ok(data, nbytes)
+	u_char *data;
+	unsigned nbytes;
+{
+	u_char *dp, *endp;
+	int c;
+
+	dp = data;
+	endp = data + nbytes;
+	while (dp < endp) {
+		c = *dp++;
+		if (c == 0x1B && dp < endp)
+			c = gsm7ext_decode_table[*dp++];
+		else
+			c = gsm7_decode_table[c];
+		if (!c)
+			return(0);
+	}
+	return(1);
+}
+
+static void
+print_alpha_field_gsmdecode(data, nbytes, outf)
+	u_char *data;
+	unsigned nbytes;
+	FILE *outf;
+{
+	u_char *dp, *endp;
+	int c;
+
+	dp = data;
+	endp = data + nbytes;
+	putc('"', outf);
+	while (dp < endp) {
+		c = *dp++;
+		if (c == 0x1B && dp < endp)
+			c = gsm7ext_decode_table[*dp++];
+		else
+			c = gsm7_decode_table[c];
+		if (c == '\n') {
+			putc('\\', outf);
+			putc('n', outf);
+			continue;
+		}
+		if (c == '\r') {
+			putc('\\', outf);
+			putc('r', outf);
+			continue;
+		}
+		if (c == '"' || c == '\\')
+			putc('\\', outf);
+		putc(c, outf);
+	}
+	putc('"', outf);
+}
+
+static void
+print_alpha_field_hex(data, nbytes, outf)
+	u_char *data;
+	unsigned nbytes;
+	FILE *outf;
+{
+	u_char *dp, *endp;
+
+	fputs("HEX ", outf);
+	dp = data;
+	endp = data + nbytes;
+	while (dp < endp)
+		fprintf(outf, "%02X", *dp++);
+}
+
+void
+print_alpha_field(data, nbytes, outf)
+	u_char *data;
+	unsigned nbytes;
+	FILE *outf;
+{
+	if (!nbytes) {
+		fputs("\"\"", outf);
+		return;
+	}
+	if (data[0] & 0x80) {
+		print_alpha_field_hex(data, nbytes, outf);
+		return;
+	}
+	if (is_gsm7_string_ok(data, nbytes))
+		print_alpha_field_gsmdecode(data, nbytes, outf);
+	else
+		print_alpha_field_hex(data, nbytes, outf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simtool/alpha_valid.c	Mon Jan 25 04:54:47 2021 +0000
@@ -0,0 +1,152 @@
+/*
+ * This module contains functions for validating alpha fields
+ * that exist in various SIM files.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static
+validate_classic_gsm(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp;
+	unsigned n;
+
+	dp = data;
+	for (n = 0; n < nbytes; n++) {
+		if (*dp == 0xFF)
+			break;
+		if (*dp & 0x80)
+			return(-1);
+		dp++;
+	}
+	if (textlenp)
+		*textlenp = n;
+	for (; n < nbytes; n++)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_ucs2_80(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp, *endp;
+
+	if (nbytes < 3)
+		return(-1);
+	dp = data + 1;
+	endp = data + nbytes;
+	while (dp < endp) {
+		if (dp + 1 == endp) {
+			if (*dp != 0xFF)
+				return(-1);
+			if (textlenp)
+				*textlenp = dp - data;
+			return(0);
+		}
+		if (dp[0] == 0xFF && dp[1] == 0xFF)
+			break;
+		dp += 2;
+	}
+	if (textlenp)
+		*textlenp = dp - data;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_ucs2_81(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp, *endp;
+	unsigned textlen;
+
+	if (nbytes < 4)
+		return(-1);
+	if (!data[1])
+		return(-1);
+	textlen = data[1] + 3;
+	if (textlen > nbytes)
+		return(-1);
+	if (textlenp)
+		*textlenp = textlen;
+	dp = data + textlen;
+	endp = data + nbytes;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_ucs2_82(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp, *endp;
+	unsigned textlen;
+
+	if (nbytes < 5)
+		return(-1);
+	if (!data[1])
+		return(-1);
+	textlen = data[1] + 4;
+	if (textlen > nbytes)
+		return(-1);
+	if (textlenp)
+		*textlenp = textlen;
+	dp = data + textlen;
+	endp = data + nbytes;
+	while (dp < endp)
+		if (*dp++ != 0xFF)
+			return(-1);
+	return(0);
+}
+
+static
+validate_empty(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	u_char *dp;
+	unsigned n;
+
+	dp = data;
+	for (n = 0; n < nbytes; n++)
+		if (*dp++ != 0xFF)
+			return(-1);
+	if (textlenp)
+		*textlenp = 0;
+	return(0);
+}
+
+validate_alpha_field(data, nbytes, textlenp)
+	u_char *data;
+	unsigned nbytes, *textlenp;
+{
+	if (data[0] < 0x80)
+		return validate_classic_gsm(data, nbytes, textlenp);
+	switch (data[0]) {
+	case 0x80:
+		return validate_ucs2_80(data, nbytes, textlenp);
+	case 0x81:
+		return validate_ucs2_81(data, nbytes, textlenp);
+	case 0x82:
+		return validate_ucs2_82(data, nbytes, textlenp);
+	case 0xFF:
+		return validate_empty(data, nbytes, textlenp);
+	default:
+		return -1;
+	}
+}
--- a/simtool/dispatch.c	Mon Jan 25 02:16:16 2021 +0000
+++ b/simtool/dispatch.c	Mon Jan 25 04:54:47 2021 +0000
@@ -20,6 +20,7 @@
 extern int cmd_restore_file();
 extern int cmd_savebin();
 extern int cmd_select();
+extern int cmd_spn();
 extern int cmd_telecom_sum();
 extern int cmd_update_bin();
 extern int cmd_update_rec();
@@ -50,6 +51,7 @@
 	{"savebin", 2, 2, cmd_savebin},
 	{"select", 1, 1, cmd_select},
 	{"sim-resp", 0, 0, display_sim_resp_in_hex},
+	{"spn", 0, 0, cmd_spn},
 	{"telecom-sum", 0, 0, cmd_telecom_sum},
 	{"update-bin", 2, 2, cmd_update_bin},
 	{"update-rec", 2, 2, cmd_update_rec},
--- a/simtool/hlread.c	Mon Jan 25 02:16:16 2021 +0000
+++ b/simtool/hlread.c	Mon Jan 25 04:54:47 2021 +0000
@@ -92,3 +92,35 @@
 	printf("%s parity=%c len=%u\n", buf + 1, buf[0], sim_resp_data[0]);
 	return(0);
 }
+
+cmd_spn()
+{
+	int rc;
+	unsigned textlen;
+
+	rc = select_op(DF_GSM);
+	if (rc < 0)
+		return(rc);
+	rc = select_op(EF_SPN);
+	if (rc < 0)
+		return(rc);
+	rc = parse_ef_select_response();
+	if (rc < 0)
+		return(rc);
+	if (curfile_structure != 0x00 || curfile_total_size != 17) {
+		fprintf(stderr, "error: expected transparent EF of 17 bytes\n");
+		return(-1);
+	}
+	rc = readbin_op(0, 17);
+	if (rc < 0)
+		return(rc);
+	printf("Display condition: %02X\n", sim_resp_data[0]);
+	printf("SPN: ");
+	rc = validate_alpha_field(sim_resp_data + 1, 16, &textlen);
+	if (rc >= 0)
+		print_alpha_field(sim_resp_data, textlen, stdout);
+	else
+		printf("malformed alpha field");
+	putchar('\n');
+	return(0);
+}