# HG changeset patch # User Mychaela Falconia # Date 1613082525 0 # Node ID f7145c77b7fbb33a012f561bd061bfa0237d68bf starting libcommon: factored out of fc-simtool diff -r 000000000000 -r f7145c77b7fb .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,3 @@ +syntax: regexp + +\.[oa]$ diff -r 000000000000 -r f7145c77b7fb libcommon/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/Makefile Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,14 @@ +CC= gcc +CFLAGS= -O2 -I/usr/include/PCSC +OBJS= alpha_decode.o alpha_valid.o apdu.o atr.o cardconnect.o exit.o \ + hexdump.o hexread.o hexstr.o names.o +LIB= libcommon.a + +all: ${LIB} + +${LIB}: ${OBJS} + ar rcu $@ ${OBJS} + ranlib $@ + +clean: + rm -f *.[oa] errs diff -r 000000000000 -r f7145c77b7fb libcommon/alpha_decode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/alpha_decode.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,132 @@ +/* + * This module contains functions for decoding and displaying alpha fields + * that exist in various SIM files. + */ + +#include +#include +#include +#include +#include + +static char gsm7_decode_table[128] = { + '@', 0, '$', 0, 0, 0, 0, 0, + 0, 0, '\n', 0, 0, '\r', 0, 0, + 0, '_', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + ' ', '!', '"', '#', 0, '%', '&', 0x27, + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 0, 0, 0, 0, 0, + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0, 0, 0, 0, 0 +}; + +static char gsm7ext_decode_table[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0, '\\', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0, + '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static +is_gsm7_string_ok(data, nbytes) + u_char *data; + unsigned nbytes; +{ + u_char *dp, *endp; + int c; + + dp = data; + endp = data + nbytes; + while (dp < endp) { + c = *dp++; + if (c == 0x1B && dp < endp) + c = gsm7ext_decode_table[*dp++]; + else + c = gsm7_decode_table[c]; + if (!c) + return(0); + } + return(1); +} + +static void +print_alpha_field_gsmdecode(data, nbytes, outf) + u_char *data; + unsigned nbytes; + FILE *outf; +{ + u_char *dp, *endp; + int c; + + dp = data; + endp = data + nbytes; + putc('"', outf); + while (dp < endp) { + c = *dp++; + if (c == 0x1B && dp < endp) + c = gsm7ext_decode_table[*dp++]; + else + c = gsm7_decode_table[c]; + if (c == '\n') { + putc('\\', outf); + putc('n', outf); + continue; + } + if (c == '\r') { + putc('\\', outf); + putc('r', outf); + continue; + } + if (c == '"' || c == '\\') + putc('\\', outf); + putc(c, outf); + } + putc('"', outf); +} + +static void +print_alpha_field_hex(data, nbytes, outf) + u_char *data; + unsigned nbytes; + FILE *outf; +{ + u_char *dp, *endp; + + fputs("HEX ", outf); + dp = data; + endp = data + nbytes; + while (dp < endp) + fprintf(outf, "%02X", *dp++); +} + +void +print_alpha_field(data, nbytes, outf) + u_char *data; + unsigned nbytes; + FILE *outf; +{ + if (!nbytes) { + fputs("\"\"", outf); + return; + } + if (data[0] & 0x80) { + print_alpha_field_hex(data, nbytes, outf); + return; + } + if (is_gsm7_string_ok(data, nbytes)) + print_alpha_field_gsmdecode(data, nbytes, outf); + else + print_alpha_field_hex(data, nbytes, outf); +} diff -r 000000000000 -r f7145c77b7fb libcommon/alpha_valid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/alpha_valid.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,152 @@ +/* + * This module contains functions for validating alpha fields + * that exist in various SIM files. + */ + +#include +#include +#include +#include +#include + +static +validate_classic_gsm(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp; + unsigned n; + + dp = data; + for (n = 0; n < nbytes; n++) { + if (*dp == 0xFF) + break; + if (*dp & 0x80) + return(-1); + dp++; + } + if (textlenp) + *textlenp = n; + for (; n < nbytes; n++) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_ucs2_80(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp, *endp; + + if (nbytes < 3) + return(-1); + dp = data + 1; + endp = data + nbytes; + while (dp < endp) { + if (dp + 1 == endp) { + if (*dp != 0xFF) + return(-1); + if (textlenp) + *textlenp = dp - data; + return(0); + } + if (dp[0] == 0xFF && dp[1] == 0xFF) + break; + dp += 2; + } + if (textlenp) + *textlenp = dp - data; + while (dp < endp) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_ucs2_81(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp, *endp; + unsigned textlen; + + if (nbytes < 4) + return(-1); + if (!data[1]) + return(-1); + textlen = data[1] + 3; + if (textlen > nbytes) + return(-1); + if (textlenp) + *textlenp = textlen; + dp = data + textlen; + endp = data + nbytes; + while (dp < endp) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_ucs2_82(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp, *endp; + unsigned textlen; + + if (nbytes < 5) + return(-1); + if (!data[1]) + return(-1); + textlen = data[1] + 4; + if (textlen > nbytes) + return(-1); + if (textlenp) + *textlenp = textlen; + dp = data + textlen; + endp = data + nbytes; + while (dp < endp) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_empty(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp; + unsigned n; + + dp = data; + for (n = 0; n < nbytes; n++) + if (*dp++ != 0xFF) + return(-1); + if (textlenp) + *textlenp = 0; + return(0); +} + +validate_alpha_field(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + if (data[0] < 0x80) + return validate_classic_gsm(data, nbytes, textlenp); + switch (data[0]) { + case 0x80: + return validate_ucs2_80(data, nbytes, textlenp); + case 0x81: + return validate_ucs2_81(data, nbytes, textlenp); + case 0x82: + return validate_ucs2_82(data, nbytes, textlenp); + case 0xFF: + return validate_empty(data, nbytes, textlenp); + default: + return -1; + } +} diff -r 000000000000 -r f7145c77b7fb libcommon/apdu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/apdu.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include "cardif.h" + +u_char sim_resp_data[258]; +unsigned sim_resp_data_len, sim_resp_sw; + +apdu_exchange(cmd_apdu, cmd_apdu_len) + u_char *cmd_apdu; + unsigned cmd_apdu_len; +{ + LONG rv; + DWORD dwRecvLength; + u_char *sw; + + dwRecvLength = 258; + rv = SCardTransmit(hCard, SCARD_PCI_T0, cmd_apdu, cmd_apdu_len, NULL, + sim_resp_data, &dwRecvLength); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardTransmit: %s\n", + pcsc_stringify_error(rv)); + return(-1); + } + if (dwRecvLength < 2) { + fprintf(stderr, + "error: SCardTransmit response is shorter than 2 SW bytes\n"); + return(-1); + } + sim_resp_data_len = dwRecvLength - 2; + sw = sim_resp_data + sim_resp_data_len; + sim_resp_sw = (sw[0] << 8) | sw[1]; + return(0); +} diff -r 000000000000 -r f7145c77b7fb libcommon/atr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/atr.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include "cardif.h" + +#define MAX_ATR_BYTES 33 + +retrieve_atr() +{ + u_char atrbuf[MAX_ATR_BYTES]; + LONG rv; + DWORD dwAttrLen; + unsigned n; + + dwAttrLen = MAX_ATR_BYTES; + rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, atrbuf, &dwAttrLen); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardGetAttrib for ATR: %s\n", + pcsc_stringify_error(rv)); + return(-1); + } + printf("ATR:"); + for (n = 0; n < dwAttrLen; n++) + printf(" %02X", atrbuf[n]); + putchar('\n'); + return(0); +} diff -r 000000000000 -r f7145c77b7fb libcommon/cardconnect.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/cardconnect.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include + +SCARDCONTEXT hContext; +SCARDHANDLE hCard; +char *reader_name_buf; + +setup_pcsc_context() +{ + LONG rv; + + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardEstablishContext: %s\n", + pcsc_stringify_error(rv)); + exit(1); + } + return(0); +} + +get_reader_name() +{ + LONG rv; + DWORD dwReaders; + + rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardListReaders 1st call: %s\n", + pcsc_stringify_error(rv)); + SCardReleaseContext(hContext); + exit(1); + } + if (dwReaders < 1) { + fprintf(stderr, + "error: dwReaders returned by SCardListReaders() is less than 1\n"); + SCardReleaseContext(hContext); + exit(1); + } + reader_name_buf = malloc(dwReaders); + if (!reader_name_buf) { + perror("malloc for readers list"); + SCardReleaseContext(hContext); + exit(1); + } + reader_name_buf[0] = '\0'; + rv = SCardListReaders(hContext, NULL, reader_name_buf, &dwReaders); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardListReaders 2nd call: %s\n", + pcsc_stringify_error(rv)); + SCardReleaseContext(hContext); + exit(1); + } + if (reader_name_buf[0] == '\0') { + fprintf(stderr, + "error: list returned by SCardListReaders() begins with a NUL byte\n"); + SCardReleaseContext(hContext); + exit(1); + } + if (!memchr(reader_name_buf, 0, dwReaders)) { + fprintf(stderr, +"error: list returned by SCardListReaders() does not contain a NUL byte\n"); + SCardReleaseContext(hContext); + exit(1); + } + return(0); +} + +connect_to_card() +{ + LONG rv; + DWORD dwActiveProtocol; + + rv = SCardConnect(hContext, reader_name_buf, SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); + if (rv != SCARD_S_SUCCESS) { + fprintf(stderr, "SCardConnect: %s\n", pcsc_stringify_error(rv)); + SCardReleaseContext(hContext); + exit(1); + } + return(0); +} diff -r 000000000000 -r f7145c77b7fb libcommon/cardif.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/cardif.h Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,5 @@ +/* extern definitions for global vars defined in cardconnect.c */ + +extern SCARDCONTEXT hContext; +extern SCARDHANDLE hCard; +extern char *reader_name_buf; diff -r 000000000000 -r f7145c77b7fb libcommon/exit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/exit.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include "cardif.h" + +good_exit() +{ + SCardDisconnect(hCard, SCARD_UNPOWER_CARD); + SCardReleaseContext(hContext); + exit(0); +} + +error_exit() +{ + SCardDisconnect(hCard, SCARD_UNPOWER_CARD); + SCardReleaseContext(hContext); + exit(1); +} diff -r 000000000000 -r f7145c77b7fb libcommon/file_id.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/file_id.h Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,51 @@ +/* definitions of a few file IDs we find interesting */ + +#define FILEID_MF 0x3F00 + +#define DF_TELECOM 0x7F10 +#define DF_GSM 0x7F20 +#define DF_DCS1800 0x7F21 + +/* EFs under MF */ +#define EF_DIR 0x2F00 +#define EF_ICCID 0x2FE2 + +/* EFs under DF_GSM */ +#define EF_LP 0x6F05 +#define EF_IMSI 0x6F07 +#define EF_Kc 0x6F20 +#define EF_PLMNsel 0x6F30 +#define EF_HPLMN 0x6F31 +#define EF_ACMmax 0x6F37 +#define EF_SST 0x6F38 +#define EF_ACM 0x6F39 +#define EF_GID1 0x6F3E +#define EF_GID2 0x6F3F +#define EF_PUCT 0x6F41 +#define EF_CBMI 0x6F45 +#define EF_SPN 0x6F46 +#define EF_CBMID 0x6F48 +#define EF_CBMIR 0x6F50 +#define EF_BCCH 0x6F74 +#define EF_ACC 0x6F78 +#define EF_FPLMN 0x6F7B +#define EF_LOCI 0x6F7E +#define EF_AD 0x6FAD +#define EF_PHASE 0x6FAE +#define EF_ECC 0x6FB7 +#define EF_PNN 0x6FC5 +#define EF_OPL 0x6FC6 + +/* EFs under DF_TELECOM */ +#define EF_ADN 0x6F3A +#define EF_FDN 0x6F3B +#define EF_SMS 0x6F3C +#define EF_CCP 0x6F3D +#define EF_MSISDN 0x6F40 +#define EF_SMSP 0x6F42 +#define EF_SMSS 0x6F43 +#define EF_LND 0x6F44 +#define EF_SDN 0x6F49 +#define EF_EXT1 0x6F4A +#define EF_EXT2 0x6F4B +#define EF_EXT3 0x6F4C diff -r 000000000000 -r f7145c77b7fb libcommon/hexdump.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/hexdump.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,36 @@ +#include +#include +#include "simresp.h" + +display_sim_resp_in_hex() +{ + unsigned off, cc, n, c; + + for (off = 0; off < sim_resp_data_len; off += cc) { + printf("%02X:", off); + cc = 16; + if (sim_resp_data_len - off < cc) + cc = sim_resp_data_len - off; + for (n = 0; n < 16; n++) { + if (n == 0 || n == 8) + putchar(' '); + putchar(' '); + if (n < cc) + printf("%02X", sim_resp_data[off + n]); + else { + putchar(' '); + putchar(' '); + } + } + putchar(' '); + putchar(' '); + for (n = 0; n < cc; n++) { + c = sim_resp_data[off + n]; + if (c < 0x20 || c > 0x7E) + c = '.'; + putchar(c); + } + putchar('\n'); + } + return(0); +} diff -r 000000000000 -r f7145c77b7fb libcommon/hexread.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/hexread.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,56 @@ +/* + * This module contains the function for reading hex files, + * to be used in the implementation of manual write commands. + */ + +#include +#include +#include +#include +#include +#include + +read_hex_data_file(filename, databuf) + char *filename; + u_char *databuf; +{ + FILE *inf; + unsigned count; + int c, c2; + + inf = fopen(filename, "r"); + if (!inf) { + perror(filename); + return(-1); + } + for (count = 0; ; count++) { + do + c = getc(inf); + while (isspace(c)); + if (c < 0) + break; + if (!isxdigit(c)) { +inv_input: fprintf(stderr, "%s: invalid hex file input\n", + filename); + fclose(inf); + return(-1); + } + c2 = getc(inf); + if (!isxdigit(c2)) + goto inv_input; + if (count >= 255) { + fprintf(stderr, "%s: hex input data is too long\n", + filename); + fclose(inf); + return(-1); + } + databuf[count] = (decode_hex_digit(c) << 4) | + decode_hex_digit(c2); + } + fclose(inf); + if (!count) { + fprintf(stderr, "%s: no hex data input found\n", filename); + return(-1); + } + return(count); +} diff -r 000000000000 -r f7145c77b7fb libcommon/hexstr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/hexstr.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,52 @@ +/* + * This module contains the function for decoding hex strings. + */ + +#include +#include +#include +#include +#include +#include + +decode_hex_digit(c) +{ + if (c >= '0' && c <= '9') + return(c - '0'); + if (c >= 'A' && c <= 'F') + return(c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return(c - 'a' + 10); + return(-1); +} + +decode_hex_data_from_string(arg, databuf, minlen, maxlen) + char *arg; + u_char *databuf; + unsigned minlen, maxlen; +{ + unsigned count; + + for (count = 0; ; count++) { + while (isspace(*arg)) + arg++; + if (!*arg) + break; + if (!isxdigit(arg[0]) || !isxdigit(arg[1])) { + fprintf(stderr, "error: invalid hex string input\n"); + return(-1); + } + if (count >= maxlen) { + fprintf(stderr, "error: hex string is too long\n"); + return(-1); + } + databuf[count] = (decode_hex_digit(arg[0]) << 4) | + decode_hex_digit(arg[1]); + arg += 2; + } + if (count < minlen) { + fprintf(stderr, "error: hex string is too short\n"); + return(-1); + } + return(count); +} diff -r 000000000000 -r f7145c77b7fb libcommon/names.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/names.c Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,76 @@ +/* + * This module contains the table of user-friendly file names + * and a function for searching this table. + */ + +#include +#include +#include +#include +#include "file_id.h" + +static struct nametab { + char *name; + int file_id; +} name_table[] = { + {"MF", FILEID_MF}, + {"DF_GSM", DF_GSM}, + {"DF_DCS1800", DF_DCS1800}, + {"DF_TELECOM", DF_TELECOM}, + {"gsm", DF_GSM}, + {"telecom", DF_TELECOM}, + /* EFs under MF */ + {"EF_DIR", EF_DIR}, + {"EF_ICCID", EF_ICCID}, + /* EFs under DF_GSM */ + {"EF_LP", EF_LP}, + {"EF_IMSI", EF_IMSI}, + {"EF_Kc", EF_Kc}, + {"EF_PLMNsel", EF_PLMNsel}, + {"EF_HPLMN", EF_HPLMN}, + {"EF_ACMmax", EF_ACMmax}, + {"EF_SST", EF_SST}, + {"EF_ACM", EF_ACM}, + {"EF_GID1", EF_GID1}, + {"EF_GID2", EF_GID2}, + {"EF_PUCT", EF_PUCT}, + {"EF_CBMI", EF_CBMI}, + {"EF_SPN", EF_SPN}, + {"EF_CBMID", EF_CBMID}, + {"EF_CBMIR", EF_CBMIR}, + {"EF_BCCH", EF_BCCH}, + {"EF_ACC", EF_ACC}, + {"EF_FPLMN", EF_FPLMN}, + {"EF_LOCI", EF_LOCI}, + {"EF_AD", EF_AD}, + {"EF_PHASE", EF_PHASE}, + {"EF_ECC", EF_ECC}, + {"EF_PNN", EF_PNN}, + {"EF_OPL", EF_OPL}, + /* EFs under DF_TELECOM */ + {"EF_ADN", EF_ADN}, + {"EF_FDN", EF_FDN}, + {"EF_SMS", EF_SMS}, + {"EF_CCP", EF_CCP}, + {"EF_MSISDN", EF_MSISDN}, + {"EF_SMSP", EF_SMSP}, + {"EF_SMSS", EF_SMSS}, + {"EF_LND", EF_LND}, + {"EF_SDN", EF_SDN}, + {"EF_EXT1", EF_EXT1}, + {"EF_EXT2", EF_EXT2}, + {"EF_EXT3", EF_EXT3}, + /* table search terminator */ + {0, -1} +}; + +find_symbolic_file_name(soughtname) + char *soughtname; +{ + struct nametab *tp; + + for (tp = name_table; tp->name; tp++) + if (!strcmp(tp->name, soughtname)) + break; + return tp->file_id; +} diff -r 000000000000 -r f7145c77b7fb libcommon/simresp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/simresp.h Thu Feb 11 22:28:45 2021 +0000 @@ -0,0 +1,4 @@ +/* extern definitions for SIM response global vars defined in apdu.c */ + +extern u_char sim_resp_data[]; +extern unsigned sim_resp_data_len, sim_resp_sw;