changeset 43:be27d1c85861

serial: main function implemented
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 20 Mar 2021 21:49:59 +0000
parents 6cc3eea720cb
children 0bc89d61fc59
files serial/Makefile serial/exchange.c serial/hexinput.c serial/main.c
diffstat 4 files changed, 242 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/serial/Makefile	Sat Mar 20 21:17:56 2021 +0000
+++ b/serial/Makefile	Sat Mar 20 21:49:59 2021 +0000
@@ -7,8 +7,8 @@
 INSTBIN=${INSTALL_PREFIX}/bin
 
 ATR_OBJS=	atrmain.o baud_parse.o collect_atr.o invtable.o serport.o
-MAIN_OBJS=	baud_parse.o collect_atr.o invtable.o main.o serport.o spenh.o \
-		xmit.o
+MAIN_OBJS=	baud_parse.o collect_atr.o exchange.o hexinput.o invtable.o \
+		main.o serport.o spenh.o xmit.o
 
 all:	${PROGS}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/exchange.c	Sat Mar 20 21:49:59 2021 +0000
@@ -0,0 +1,183 @@
+/*
+ * This module implements the main function of our back end:
+ * exchanging APDUs with the SIM.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+
+static
+collect_one_byte()
+{
+	u_char buf;
+	int rc;
+
+	rc = collect_bytes_from_sim(&buf, 1);
+	if (rc < 0)
+		return rc;
+	else
+		return buf;
+}
+
+static void
+finish_sw(sw1, data, datalen)
+	unsigned sw1, datalen;
+	u_char *data;
+{
+	unsigned sw2, n;
+	int rc;
+
+	rc = collect_one_byte();
+	if (rc < 0) {
+		printf("back end error at SW2 Rx step\n");
+		return;
+	}
+	sw2 = rc;
+	for (n = 0; n < datalen; n++)
+		printf("%02X", data[n]);
+	printf("%02X%02X\n", sw1, sw2);
+}
+
+static void
+exchange_data_out(ins, data, datalen)
+	unsigned ins, datalen;
+	u_char *data;
+{
+	int rc;
+	unsigned null_count, bytes_sent, ack, ack1;
+
+	ack = ins & 0xFE;
+	ack1 = ~ins & 0xFE;
+	bytes_sent = 0;
+	null_count = 0;
+	for (;;) {
+		rc = collect_one_byte();
+		if (rc < 0) {
+			printf("back end error at procedure byte step\n");
+			return;
+		}
+		if (rc == 0x60) {
+			null_count++;
+			if (null_count >= 32) {
+				printf(
+		"ERROR: too many stalling NULL bytes received from SIM\n");
+				return;
+			}
+			continue;
+		}
+		if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
+			finish_sw(rc, 0, 0);
+			return;
+		}
+		if ((rc & 0xFE) == ack) {
+			if (bytes_sent >= datalen) {
+bad_xfer_req:			printf(
+		"ERROR: SIM requests more xfer after we sent everything\n");
+				return;
+			}
+			rc = send_bytes_to_sim(data + bytes_sent,
+						datalen - bytes_sent);
+			if (rc < 0) {
+				printf("back end error at data output step\n");
+				return;
+			}
+			bytes_sent = datalen;
+			continue;
+		}
+		if ((rc & 0xFE) == ack1) {
+			if (bytes_sent >= datalen)
+				goto bad_xfer_req;
+			rc = send_bytes_to_sim(data + bytes_sent, 1);
+			if (rc < 0) {
+				printf("back end error at data output step\n");
+				return;
+			}
+			bytes_sent++;
+			continue;
+		}
+		printf("ERROR: non-understood procedure byte %02X\n", rc);
+		return;
+	}
+}
+
+static void
+exchange_data_in(ins, datalen)
+	unsigned ins, datalen;
+{
+	int rc;
+	unsigned null_count, bytes_rcvd, ack, ack1;
+	u_char data[256];
+
+	if (!datalen)
+		datalen = 256;
+	ack = ins & 0xFE;
+	ack1 = ~ins & 0xFE;
+	bytes_rcvd = 0;
+	null_count = 0;
+	for (;;) {
+		rc = collect_one_byte();
+		if (rc < 0) {
+			printf("back end error at procedure byte step\n");
+			return;
+		}
+		if (rc == 0x60) {
+			null_count++;
+			if (null_count >= 32) {
+				printf(
+		"ERROR: too many stalling NULL bytes received from SIM\n");
+				return;
+			}
+			continue;
+		}
+		if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
+			finish_sw(rc, data, bytes_rcvd);
+			return;
+		}
+		if ((rc & 0xFE) == ack) {
+			if (bytes_rcvd >= datalen) {
+bad_xfer_req:			printf(
+	"ERROR: SIM requests more xfer after we received all expected data\n");
+				return;
+			}
+			rc = collect_bytes_from_sim(data + bytes_rcvd,
+						    datalen - bytes_rcvd);
+			if (rc < 0) {
+				printf("back end error at data input step\n");
+				return;
+			}
+			bytes_rcvd = datalen;
+			continue;
+		}
+		if ((rc & 0xFE) == ack1) {
+			if (bytes_rcvd >= datalen)
+				goto bad_xfer_req;
+			rc = collect_one_byte();
+			if (rc < 0) {
+				printf("back end error at data input step\n");
+				return;
+			}
+			data[bytes_rcvd++] = rc;
+			continue;
+		}
+		printf("ERROR: non-understood procedure byte %02X\n", rc);
+		return;
+	}
+}
+
+void
+apdu_exchange(cmd_apdu, cmd_apdu_len)
+	u_char *cmd_apdu;
+	unsigned cmd_apdu_len;
+{
+	int rc;
+
+	rc = send_bytes_to_sim(cmd_apdu, 5);
+	if (rc < 0) {
+		printf("back end error at the command sending step\n");
+		return;
+	}
+	if (cmd_apdu_len > 5)
+		exchange_data_out(cmd_apdu[1], cmd_apdu + 5, cmd_apdu_len - 5);
+	else
+		exchange_data_in(cmd_apdu[1], cmd_apdu[4]);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial/hexinput.c	Sat Mar 20 21:49:59 2021 +0000
@@ -0,0 +1,42 @@
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+
+static
+decode_hex_digit(c)
+{
+	if (isdigit(c))
+		return c - '0';
+	else if (islower(c))
+		return c - 'a' + 10;
+	else
+		return c - 'A' + 10;
+}
+
+parse_hex_input(inbuf, outbuf)
+	char *inbuf;
+	u_char *outbuf;
+{
+	char *cp;
+	unsigned count;
+
+	count = 0;
+	for (cp = inbuf; ; ) {
+		while (isspace(*cp))
+			cp++;
+		if (!*cp)
+			break;
+		if (!isxdigit(cp[0]) || !isxdigit(cp[1])) {
+			printf("error: invalid hex APDU input\n");
+			return(-1);
+		}
+		if (count >= 260) {
+			printf("error: command APDU is too long\n");
+			return(-1);
+		}
+		outbuf[count++] = (decode_hex_digit(cp[0]) << 4) |
+				  decode_hex_digit(cp[1]);
+		cp += 2;
+	}
+	return count;
+}
--- a/serial/main.c	Sat Mar 20 21:17:56 2021 +0000
+++ b/serial/main.c	Sat Mar 20 21:49:59 2021 +0000
@@ -10,6 +10,8 @@
 main(argc, argv)
 	char **argv;
 {
+	char inbuf[576];
+	u_char cmd[260];
 	int rc;
 
 	if (argc != 3) {
@@ -27,7 +29,19 @@
 	print_atr("A");
 	if (baud_spenh)
 		spenh_logic();
+	putchar('\n');
+	fflush(stdout);
 
-	/* remaining logic to be implemented */
+	for (; fgets(inbuf, sizeof inbuf, stdin); fflush(stdout)) {
+		rc = parse_hex_input(inbuf, cmd);
+		if (rc < 0)
+			continue;
+		if (rc < 5) {
+			printf("error: command APDU is too short\n");
+			continue;
+		}
+		apdu_exchange(cmd, rc);
+	}
+
 	exit(0);
 }