FreeCalypso > hg > fc-sim-tools
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); }