# HG changeset patch # User Mychaela Falconia # Date 1615698454 0 # Node ID deeeef558279456744bbede95ab1913d2ad72373 # Parent 45ea06eaa9fdc2bb164180f0bb8d309fe57b0893 fcsim-calypso-be put together diff -r 45ea06eaa9fd -r deeeef558279 .hgignore --- 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$ diff -r 45ea06eaa9fd -r deeeef558279 calypso/Makefile --- /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 diff -r 45ea06eaa9fd -r deeeef558279 calypso/main.c --- /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 +#include +#include +#include +#include + +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); +} diff -r 45ea06eaa9fd -r deeeef558279 calypso/targetfd.c --- /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 +#include +#include + +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); +} diff -r 45ea06eaa9fd -r deeeef558279 calypso/tpinterf.c --- /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 +#include +#include +#include +#include +#include +#include +#include + +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); +}