FreeCalypso > hg > fc-sim-tools
view serial/collect_atr.c @ 58:871281cb0555
doc/Low-level-commands: apdu-checksw documented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 23 Mar 2021 00:21:02 +0000 |
parents | 1d96f3b4f155 |
children |
line wrap: on
line source
/* * This module contains the code for collecting ATR bytes from the SIM, * as well as subsequent byte Rx. */ #include <sys/types.h> #include <sys/time.h> #include <sys/errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> extern int target_fd; #define MAX_ATR_BYTES 33 extern unsigned char inverse_coding_table[256]; u_char atr_buf[MAX_ATR_BYTES]; unsigned atr_length; int inverse_coding; void invert_bytes(buf, nbytes) u_char *buf; unsigned nbytes; { unsigned n; for (n = 0; n < nbytes; n++) buf[n] = inverse_coding_table[buf[n]]; } collect_bytes_from_sim(buf, expect_len) u_char *buf; unsigned expect_len; { fd_set fds; struct timeval tv; unsigned rcvd; int cc; for (rcvd = 0; rcvd < expect_len; ) { FD_ZERO(&fds); FD_SET(target_fd, &fds); tv.tv_sec = 2; tv.tv_usec = 0; cc = select(target_fd+1, &fds, NULL, NULL, &tv); if (cc < 0) { if (errno == EINTR) continue; perror("select"); return(-1); } if (cc < 1) { fprintf(stderr, "error: timeout waiting for byte(s) from SIM\n"); return(-1); } cc = read(target_fd, buf + rcvd, expect_len - rcvd); if (cc <= 0) { perror("read after successful select"); return(-1); } rcvd += cc; } if (inverse_coding) invert_bytes(buf, rcvd); return(0); } check_atr_tck() { unsigned b, p; b = 0; for (p = 1; p < atr_length; p++) b ^= atr_buf[p]; if (b) { fprintf(stderr, "error: ATR checksum is bad\n"); return(-1); } return(0); } collect_atr() { int rc; unsigned count, y, nhist, have_tck; rc = collect_bytes_from_sim(atr_buf, 2); if (rc < 0) return(rc); if (atr_buf[0] == 0x3B) { /* direct convention */ } else if (atr_buf[0] == 0x03) { /* inverse convention */ inverse_coding = 1; atr_buf[0] = 0x3F; atr_buf[1] = inverse_coding_table[atr_buf[1]]; } else { fprintf(stderr, "error: received TS=0x%02X, matches neither convention\n", atr_buf[0]); return(-1); } atr_length = 2; nhist = atr_buf[1] & 0x0F; y = atr_buf[1] & 0xF0; have_tck = 0; while (y) { count = 0; if (y & 0x10) count++; if (y & 0x20) count++; if (y & 0x40) count++; if (y & 0x80) count++; if (atr_length + count > MAX_ATR_BYTES) { atr_too_long: fprintf(stderr, "error: ATR exceeds 33 byte limit\n"); return(-1); } rc = collect_bytes_from_sim(atr_buf + atr_length, count); if (rc < 0) return(rc); atr_length += count; if (y & 0x80) { y = atr_buf[atr_length-1] & 0xF0; if (atr_buf[atr_length-1] & 0x0F) have_tck = 1; } else y = 0; } count = nhist + have_tck; if (count) { if (atr_length + count > MAX_ATR_BYTES) goto atr_too_long; rc = collect_bytes_from_sim(atr_buf + atr_length, count); if (rc < 0) return(rc); atr_length += count; } if (have_tck) return check_atr_tck(); else return 0; } void print_atr(head) char *head; { unsigned n; fputs(head, stdout); for (n = 0; n < atr_length; n++) { printf(" %02X", atr_buf[n]); } putchar('\n'); }