FreeCalypso > hg > fc-pcsc-tools
view simtool/select.c @ 47:ae3342497fea
fc-simtool verify-hex command added
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 13 Feb 2021 00:57:57 +0000 |
parents | 2071b28cd0c7 |
children | b0982c0cf54d |
line wrap: on
line source
#include <sys/types.h> #include <ctype.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <stdlib.h> #include "simresp.h" #include "curfile.h" select_op(file_id) unsigned file_id; { u_char cmd[7]; int rc; unsigned expect_resp_len; /* SELECT command APDU */ cmd[0] = 0xA0; cmd[1] = 0xA4; cmd[2] = 0; cmd[3] = 0; cmd[4] = 2; cmd[5] = file_id >> 8; cmd[6] = file_id; rc = apdu_exchange(cmd, 7); if (rc < 0) return(rc); if ((sim_resp_sw & 0xFF00) != 0x9F00) { fprintf(stderr, "error or unexpected SW response to SELECT of 0x%04X: %04X\n", file_id, sim_resp_sw); return(-1); } expect_resp_len = sim_resp_sw & 0xFF; /* GET RESPONSE follow-up */ cmd[1] = 0xC0; cmd[4] = expect_resp_len; rc = apdu_exchange(cmd, 5); if (rc < 0) return(rc); if (sim_resp_sw != 0x9000) { fprintf(stderr, "bad SW resp to GET RESPONSE after SELECT: %04X\n", sim_resp_sw); return(-1); } if (sim_resp_data_len != expect_resp_len) { fprintf(stderr, "error: GET RESPONSE after SELECT returned %u bytes, expected %u\n", sim_resp_data_len, expect_resp_len); return(-1); } return(0); } static void show_secret_code_status(name, byte) char *name; unsigned byte; { printf("Status of %s: %s, %u attempts left\n", name, byte & 0x80 ? "initialized" : "not initialized", byte & 0x0F); } void show_access_conditions(oper_name, cond_code) char *oper_name; unsigned cond_code; { static char *cond_names[16] = {"ALW", "CHV1", "CHV2", "RFU3", "ADM4", "ADM5", "ADM6", "ADM7", "ADM8", "ADM9", "ADM10", "ADM11", "ADM12", "ADM13", "ADM14", "NEV"}; printf("Access condition for %s: %s\n", oper_name, cond_names[cond_code]); } cmd_select(argc, argv) char **argv; { int file_id, rc; if (isxdigit(argv[1][0]) && isxdigit(argv[1][1]) && isxdigit(argv[1][2]) && isxdigit(argv[1][3]) && !argv[1][4]) file_id = strtoul(argv[1], 0, 16); else file_id = find_symbolic_file_name(argv[1]); if (file_id < 0) { fprintf(stderr, "error: file ID argument is not a hex value or a recognized symbolic name\n"); return(-1); } rc = select_op(file_id); if (rc < 0) return(rc); if (sim_resp_data_len < 14) { fprintf(stderr, "error: response length of %u bytes is too short for any file type\n", sim_resp_data_len); return(-1); } switch (sim_resp_data[6]) { case 0x01: printf("File type: MF\n"); goto mf_or_df; case 0x02: printf("File type: DF\n"); mf_or_df: if (sim_resp_data_len < 22) { fprintf(stderr, "error: response length of %u bytes is too short for MF/DF\n", sim_resp_data_len); return(-1); } printf("File characteristics: %02X\n", sim_resp_data[13]); printf("Number of DF children: %u\n", sim_resp_data[14]); printf("Number of EF children: %u\n", sim_resp_data[15]); printf("Number of secret codes: %u\n", sim_resp_data[16]); show_secret_code_status("PIN1", sim_resp_data[18]); show_secret_code_status("PUK1", sim_resp_data[19]); show_secret_code_status("PIN2", sim_resp_data[20]); show_secret_code_status("PUK2", sim_resp_data[21]); break; case 0x04: printf("File type: EF\n"); curfile_total_size = (sim_resp_data[2] << 8) | sim_resp_data[3]; printf("File size: %u\n", curfile_total_size); curfile_structure = sim_resp_data[13]; switch (curfile_structure) { case 0x00: printf("Structure: transparent\n"); break; case 0x01: printf("Structure: linear fixed\n"); goto ef_record_based; case 0x03: printf("Structure: cyclic\n"); ef_record_based: if (sim_resp_data_len < 15) { fprintf(stderr, "error: response length of %u bytes is too short for record-based EF\n", sim_resp_data_len); return(-1); } printf("Record length: %u\n", sim_resp_data[14]); curfile_record_len = sim_resp_data[14]; if (curfile_record_len && curfile_total_size % curfile_record_len == 0) { curfile_record_count = curfile_total_size / curfile_record_len; printf("Number of records: %u\n", curfile_record_count); } else curfile_record_count = 0; break; default: printf("Structure: %02X (unknown)\n", curfile_structure); } printf("File status: %02X\n", sim_resp_data[11]); show_access_conditions("UPDATE", sim_resp_data[8] & 0xF); show_access_conditions("READ & SEEK", sim_resp_data[8] >> 4); show_access_conditions("INCREASE", sim_resp_data[9] >> 4); show_access_conditions("INVALIDATE", sim_resp_data[10] & 0xF); show_access_conditions("REHABILITATE", sim_resp_data[10] >> 4); break; default: printf("File type: %02X (unknown)\n", sim_resp_data[6]); } return(0); } parse_ef_select_response() { if (sim_resp_data_len < 14) { fprintf(stderr, "error: SELECT response length of %u bytes is too short\n", sim_resp_data_len); return(-1); } if (sim_resp_data[6] != 0x04) { fprintf(stderr, "error: selected file is not an EF\n"); return(-1); } curfile_total_size = (sim_resp_data[2] << 8) | sim_resp_data[3]; curfile_structure = sim_resp_data[13]; switch (curfile_structure) { case 0x00: /* transparent */ break; case 0x01: case 0x03: /* record-based */ if (sim_resp_data_len < 15) { fprintf(stderr, "error: SELECT response length of %u bytes is too short for record-based EF\n", sim_resp_data_len); return(-1); } curfile_record_len = sim_resp_data[14]; if (!curfile_record_len) { fprintf(stderr, "error: SELECT response indicates record length of 0\n"); return(-1); } if (curfile_total_size % curfile_record_len) { fprintf(stderr, "error: returned file size is not divisible by record length\n"); return(-1); } curfile_record_count = curfile_total_size / curfile_record_len; break; default: fprintf(stderr, "error: unknown EF structure code %02X\n", curfile_structure); return(-1); } return(0); }