FreeCalypso > hg > fc-sim-tools
view simtool/select.c @ 64:dba24129027e
doc/ADM-PIN-numbering article written
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 23 Mar 2021 23:30:00 +0000 |
parents | ddd767f6e15b |
children |
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" elem_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 == 0x9404) return(0); if ((sim_resp_sw & 0xFF00) == 0x9F00) return(1); fprintf(stderr, "error or unexpected SW response to SELECT of 0x%04X: %04X\n", file_id, sim_resp_sw); return(-1); } 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(outf, name, byte) FILE *outf; char *name; unsigned byte; { fprintf(outf, "Status of %s: %s, %u attempts left\n", name, byte & 0x80 ? "initialized" : "not initialized", byte & 0x0F); } void show_access_conditions(outf, oper_name, cond_code) FILE *outf; 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"}; fprintf(outf, "Access condition for %s: %s\n", oper_name, cond_names[cond_code]); } cmd_select(argc, argv, outf) char **argv; FILE *outf; { 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: fprintf(outf, "File type: MF\n"); goto mf_or_df; case 0x02: fprintf(outf, "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); } fprintf(outf, "File characteristics: %02X\n", sim_resp_data[13]); fprintf(outf, "Number of DF children: %u\n", sim_resp_data[14]); fprintf(outf, "Number of EF children: %u\n", sim_resp_data[15]); fprintf(outf, "Number of secret codes: %u\n", sim_resp_data[16]); show_secret_code_status(outf, "PIN1", sim_resp_data[18]); show_secret_code_status(outf, "PUK1", sim_resp_data[19]); show_secret_code_status(outf, "PIN2", sim_resp_data[20]); show_secret_code_status(outf, "PUK2", sim_resp_data[21]); break; case 0x04: fprintf(outf, "File type: EF\n"); curfile_total_size = (sim_resp_data[2] << 8) | sim_resp_data[3]; fprintf(outf, "File size: %u\n", curfile_total_size); curfile_structure = sim_resp_data[13]; switch (curfile_structure) { case 0x00: fprintf(outf, "Structure: transparent\n"); break; case 0x01: fprintf(outf, "Structure: linear fixed\n"); goto ef_record_based; case 0x03: fprintf(outf, "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); } fprintf(outf, "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; fprintf(outf, "Number of records: %u\n", curfile_record_count); } else curfile_record_count = 0; break; default: fprintf(outf, "Structure: %02X (unknown)\n", curfile_structure); } fprintf(outf, "File status: %02X\n", sim_resp_data[11]); show_access_conditions(outf, "UPDATE", sim_resp_data[8] & 0xF); show_access_conditions(outf, "READ & SEEK", sim_resp_data[8] >> 4); show_access_conditions(outf, "INCREASE", sim_resp_data[9] >> 4); show_access_conditions(outf, "INVALIDATE", sim_resp_data[10] & 0xF); show_access_conditions(outf, "REHABILITATE", sim_resp_data[10] >> 4); break; default: fprintf(outf, "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; if (curfile_record_count > 255) { fprintf(stderr, "error: EF record count exceeds protocol limit\n"); return(-1); } break; default: fprintf(stderr, "error: unknown EF structure code %02X\n", curfile_structure); return(-1); } return(0); }