changeset 4:deeeef558279

fcsim-calypso-be put together
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Mar 2021 05:07:34 +0000
parents 45ea06eaa9fd
children f6b03af63bf7
files .hgignore calypso/Makefile calypso/main.c calypso/targetfd.c calypso/tpinterf.c
diffstat 5 files changed, 346 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Mar 14 02:21:49 2021 +0000
+++ b/.hgignore	Sun Mar 14 05:07:34 2021 +0000
@@ -2,6 +2,8 @@
 
 \.[oa]$
 
+^calypso/fcsim-calypso-be$
+
 ^pcsc/fc-pcsc-atr$
 ^pcsc/fc-pcsc-backend$
 ^pcsc/fc-pcsc-list$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calypso/Makefile	Sun Mar 14 05:07:34 2021 +0000
@@ -0,0 +1,21 @@
+CC=	gcc
+CFLAGS=	-O2
+PROGS=	fcsim-calypso-be
+
+INSTALL_PREFIX=	/opt/freecalypso
+
+INSTBIN=${INSTALL_PREFIX}/bin
+
+MAIN_OBJS=	main.o targetfd.o tpinterf.o
+
+all:	${PROGS}
+
+fcsim-calypso-be:	${MAIN_OBJS}
+	${CC} ${CFLAGS} -o $@ ${MAIN_OBJS}
+
+install:
+	mkdir -p ${INSTBIN}
+	install -c fcsim-calypso-be ${INSTBIN}
+
+clean:
+	rm -f ${PROGS} *.o
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calypso/main.c	Sun Mar 14 05:07:34 2021 +0000
@@ -0,0 +1,104 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+static
+is_string_all_hex(str)
+	char *str;
+{
+	char *cp;
+
+	for (cp = str; *cp; cp++)
+		if (!isxdigit(*cp))
+			return(0);
+	return(1);
+}
+
+cmd_exchange(input)
+	char *input;
+{
+	char *targv[3];
+	int rc;
+
+	targv[0] = "X";
+	targv[1] = input;
+	targv[2] = 0;
+
+	tpinterf_make_cmd(targv);
+	rc = tpinterf_send_cmd();
+	if (rc < 0)
+		return(rc);
+	return tpinterf_pass_output(20);
+}
+
+cmd_atr()
+{
+	static char *atr_argv[2] = {"atr", 0};
+	int rc;
+
+	tpinterf_make_cmd(atr_argv);
+	rc = tpinterf_send_cmd();
+	if (rc < 0)
+		return(rc);
+	return tpinterf_pass_output(1);
+}
+
+cmd_poweroff()
+{
+	static char *poweroff_argv[2] = {"poweroff", 0};
+
+	tpinterf_make_cmd(poweroff_argv);
+	tpinterf_send_cmd();
+}
+
+main(argc, argv)
+	char **argv;
+{
+	char inbuf[576], *cp;
+	unsigned len;
+
+	parse_target_fd_opt(argc, argv);
+	putchar('\n');
+
+	while (fgets(inbuf, sizeof inbuf, stdin)) {
+		cp = index(inbuf, '\n');
+		if (!cp) {
+			printf("back end error: missing newline on input\n");
+			continue;
+		}
+		*cp = '\0';
+		if (!strcmp(inbuf, "atr")) {
+			cmd_atr();
+			continue;
+		}
+		if (!strcmp(inbuf, "poweroff")) {
+			cmd_poweroff();
+			exit(0);
+		}
+		if (!is_string_all_hex(inbuf)) {
+			printf("back end error: input is not all hex\n");
+			continue;
+		}
+		len = strlen(inbuf);
+		if (len & 1) {
+			printf(
+			"back end error: input has odd number of hex digits\n");
+			continue;
+		}
+		if (len < 10) {
+			printf(
+		"back end error: input is too short for command APDU\n");
+			continue;
+		}
+		if (len > 520) {
+			printf(
+			"back end error: input is too long for command APDU\n");
+			continue;
+		}
+		cmd_exchange(inbuf);
+	}
+
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calypso/targetfd.c	Sun Mar 14 05:07:34 2021 +0000
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int target_fd;
+
+parse_target_fd_opt(argc, argv)
+	char **argv;
+{
+	extern char *optarg;
+	int c;
+
+	while ((c = getopt(argc, argv, "C:")) != EOF) {
+		switch (c) {
+		case 'C':
+			target_fd = atoi(optarg);
+			continue;
+		case '?':
+		default:
+			/* error msg already printed */
+			exit(1);
+		}
+	}
+	if (!target_fd) {
+		fprintf(stderr, "error: target fd must be given with -C\n");
+		exit(1);
+	}
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calypso/tpinterf.c	Sun Mar 14 05:07:34 2021 +0000
@@ -0,0 +1,190 @@
+/*
+ * This code is based on loadtools/tpinterf.c from FC host tools,
+ * modified for our different application of interfacing between
+ * simagent below and fc-simtool above.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int errno;
+
+extern int target_fd;
+
+/* definition matches target-utils/libcommon/cmdentry.c */
+#define	MAXCMD	527
+
+/*
+ * static buffer between tpinterf_make_cmd and tpinterf_send_cmd
+ *
+ * We store the command with an ending \r\n so we can use it for
+ * matching the received echo as well, hence the sizing of the
+ * buffer.
+ */
+static char cmdbuf[MAXCMD+2];
+static int cmdlen;
+
+static int
+arg_chars_valid(arg)
+	char *arg;
+{
+	char *cp;
+
+	for (cp = arg; *cp; cp++)
+		if (*cp < ' ' || *cp > '~')
+			return(0);
+	return(1);
+}
+
+/*
+ * This function takes a command for the target in argv form and
+ * converts it to a space-separated continuous string which can be
+ * passed as tty "keyboard" input to the target, enforcing length
+ * and character validity limits in the process.  The output is
+ * stored in an internal static buffer for subsequent
+ * tpinterf_send_cmd().
+ *
+ * Return value: 0 if everything OK, or -1 if some constraint is
+ * violated.
+ */
+tpinterf_make_cmd(argv)
+	char **argv;
+{
+	int arglen;
+	char **ap, *dp;
+
+	dp = cmdbuf;
+	cmdlen = 0;
+	for (ap = argv; *ap; ap++) {
+		arglen = strlen(*ap);
+		if (ap != argv)
+			arglen++;	/* separating space */
+		if (arglen > MAXCMD - cmdlen)
+			return(-1);
+		if (!arg_chars_valid(*ap))
+			return(-1);
+		if (ap != argv)
+			*dp++ = ' ';
+		strcpy(dp, *ap);
+		dp += strlen(*ap);
+		cmdlen += arglen;
+	}
+	*dp++ = '\r';
+	*dp = '\n';
+	return(0);
+}
+
+/*
+ * This function sends the previously-constructed command to the target,
+ * and collects the expected echo.
+ *
+ * Return value: 0 if successful, -1 on errors (timeout or wrong response)
+ */
+tpinterf_send_cmd()
+{
+	char echobuf[MAXCMD+2];
+	fd_set fds;
+	struct timeval tv;
+	int rcvd, cc;
+
+	write(target_fd, cmdbuf, cmdlen + 1);
+	for (rcvd = 0; rcvd < cmdlen + 2; ) {
+		FD_ZERO(&fds);
+		FD_SET(target_fd, &fds);
+		tv.tv_sec = 1;
+		tv.tv_usec = 0;
+		cc = select(target_fd+1, &fds, NULL, NULL, &tv);
+		if (cc < 0) {
+			if (errno == EINTR)
+				continue;
+			printf("back end error: failed select\n");
+			return(-1);
+		}
+		if (cc < 1) {
+			printf(
+			"back end error: timeout waiting for command echo\n");
+			return(-1);
+		}
+		cc = read(target_fd, echobuf + rcvd, cmdlen + 2 - rcvd);
+		if (cc <= 0) {
+			printf(
+		"back end error: failed read after successful select\n");
+			return(-1);
+		}
+		rcvd += cc;
+	}
+	if (bcmp(echobuf, cmdbuf, cmdlen + 2)) {
+		printf("back end error: command echo mismatch\n");
+		return(-1);
+	} else
+		return(0);
+}
+
+/*
+ * This functions reads the serial output from the target until a
+ * '=' prompt is received.  All intermediate output is passed to
+ * stdout, with some hacks specific to this SIM interface back end.
+ */
+tpinterf_pass_output(timeout)
+{
+	char buf[1024], *cp;
+	fd_set fds;
+	struct timeval tv;
+	int cc, newline = 1, termflag = 0;
+	unsigned goodchar;
+
+	for (goodchar = 0; ; ) {
+		FD_ZERO(&fds);
+		FD_SET(target_fd, &fds);
+		tv.tv_sec = timeout;
+		tv.tv_usec = 0;
+		cc = select(target_fd+1, &fds, NULL, NULL, &tv);
+		if (cc < 0) {
+			if (errno == EINTR)
+				continue;
+			printf("back end error: failed select\n");
+			return(-1);
+		}
+		if (cc < 1) {
+			printf(
+		"back end error: timeout waiting for simagent response\n");
+			return(-1);
+		}
+		cc = read(target_fd, buf + goodchar, sizeof(buf) - goodchar);
+		if (cc <= 0) {
+			printf(
+		"back end error: failed read after successful select\n");
+			return(-1);
+		}
+		for (cp = buf + goodchar; cc; cp++) {
+			cc--;
+			if (*cp == '=' && newline && !cc)
+				break;
+			if (*cp == '\n') {
+				newline = 1;
+				termflag = 1;
+				continue;
+			}
+			newline = 0;
+			if (*cp == '\r')
+				termflag = 1;
+			if (!termflag)
+				goodchar++;
+			if (goodchar >= 516)
+				termflag = 1;
+		}
+	}
+	if (!goodchar) {
+		printf("back end error: empty output from simagent\n");
+		return(-1);
+	}
+	buf[goodchar] = '\0';
+	puts(buf);
+	return(0);
+}