comparison simtool/select.c @ 1:2071b28cd0c7

simtool: first refactored version
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 11 Feb 2021 23:04:28 +0000
parents
children b0982c0cf54d
comparison
equal deleted inserted replaced
0:f7145c77b7fb 1:2071b28cd0c7
1 #include <sys/types.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "simresp.h"
8 #include "curfile.h"
9
10 select_op(file_id)
11 unsigned file_id;
12 {
13 u_char cmd[7];
14 int rc;
15 unsigned expect_resp_len;
16
17 /* SELECT command APDU */
18 cmd[0] = 0xA0;
19 cmd[1] = 0xA4;
20 cmd[2] = 0;
21 cmd[3] = 0;
22 cmd[4] = 2;
23 cmd[5] = file_id >> 8;
24 cmd[6] = file_id;
25 rc = apdu_exchange(cmd, 7);
26 if (rc < 0)
27 return(rc);
28 if ((sim_resp_sw & 0xFF00) != 0x9F00) {
29 fprintf(stderr,
30 "error or unexpected SW response to SELECT of 0x%04X: %04X\n",
31 file_id, sim_resp_sw);
32 return(-1);
33 }
34 expect_resp_len = sim_resp_sw & 0xFF;
35 /* GET RESPONSE follow-up */
36 cmd[1] = 0xC0;
37 cmd[4] = expect_resp_len;
38 rc = apdu_exchange(cmd, 5);
39 if (rc < 0)
40 return(rc);
41 if (sim_resp_sw != 0x9000) {
42 fprintf(stderr,
43 "bad SW resp to GET RESPONSE after SELECT: %04X\n",
44 sim_resp_sw);
45 return(-1);
46 }
47 if (sim_resp_data_len != expect_resp_len) {
48 fprintf(stderr,
49 "error: GET RESPONSE after SELECT returned %u bytes, expected %u\n",
50 sim_resp_data_len, expect_resp_len);
51 return(-1);
52 }
53 return(0);
54 }
55
56 static void
57 show_secret_code_status(name, byte)
58 char *name;
59 unsigned byte;
60 {
61 printf("Status of %s: %s, %u attempts left\n", name,
62 byte & 0x80 ? "initialized" : "not initialized",
63 byte & 0x0F);
64 }
65
66 void
67 show_access_conditions(oper_name, cond_code)
68 char *oper_name;
69 unsigned cond_code;
70 {
71 static char *cond_names[16] =
72 {"ALW", "CHV1", "CHV2", "RFU3",
73 "ADM4", "ADM5", "ADM6", "ADM7",
74 "ADM8", "ADM9", "ADM10", "ADM11",
75 "ADM12", "ADM13", "ADM14", "NEV"};
76
77 printf("Access condition for %s: %s\n", oper_name,
78 cond_names[cond_code]);
79 }
80
81 cmd_select(argc, argv)
82 char **argv;
83 {
84 int file_id, rc;
85
86 if (isxdigit(argv[1][0]) && isxdigit(argv[1][1]) &&
87 isxdigit(argv[1][2]) && isxdigit(argv[1][3]) && !argv[1][4])
88 file_id = strtoul(argv[1], 0, 16);
89 else
90 file_id = find_symbolic_file_name(argv[1]);
91 if (file_id < 0) {
92 fprintf(stderr,
93 "error: file ID argument is not a hex value or a recognized symbolic name\n");
94 return(-1);
95 }
96 rc = select_op(file_id);
97 if (rc < 0)
98 return(rc);
99 if (sim_resp_data_len < 14) {
100 fprintf(stderr,
101 "error: response length of %u bytes is too short for any file type\n",
102 sim_resp_data_len);
103 return(-1);
104 }
105 switch (sim_resp_data[6]) {
106 case 0x01:
107 printf("File type: MF\n");
108 goto mf_or_df;
109 case 0x02:
110 printf("File type: DF\n");
111 mf_or_df:
112 if (sim_resp_data_len < 22) {
113 fprintf(stderr,
114 "error: response length of %u bytes is too short for MF/DF\n",
115 sim_resp_data_len);
116 return(-1);
117 }
118 printf("File characteristics: %02X\n", sim_resp_data[13]);
119 printf("Number of DF children: %u\n", sim_resp_data[14]);
120 printf("Number of EF children: %u\n", sim_resp_data[15]);
121 printf("Number of secret codes: %u\n", sim_resp_data[16]);
122 show_secret_code_status("PIN1", sim_resp_data[18]);
123 show_secret_code_status("PUK1", sim_resp_data[19]);
124 show_secret_code_status("PIN2", sim_resp_data[20]);
125 show_secret_code_status("PUK2", sim_resp_data[21]);
126 break;
127 case 0x04:
128 printf("File type: EF\n");
129 curfile_total_size = (sim_resp_data[2] << 8) | sim_resp_data[3];
130 printf("File size: %u\n", curfile_total_size);
131 curfile_structure = sim_resp_data[13];
132 switch (curfile_structure) {
133 case 0x00:
134 printf("Structure: transparent\n");
135 break;
136 case 0x01:
137 printf("Structure: linear fixed\n");
138 goto ef_record_based;
139 case 0x03:
140 printf("Structure: cyclic\n");
141 ef_record_based:
142 if (sim_resp_data_len < 15) {
143 fprintf(stderr,
144 "error: response length of %u bytes is too short for record-based EF\n",
145 sim_resp_data_len);
146 return(-1);
147 }
148 printf("Record length: %u\n", sim_resp_data[14]);
149 curfile_record_len = sim_resp_data[14];
150 if (curfile_record_len &&
151 curfile_total_size % curfile_record_len == 0) {
152 curfile_record_count =
153 curfile_total_size / curfile_record_len;
154 printf("Number of records: %u\n",
155 curfile_record_count);
156 } else
157 curfile_record_count = 0;
158 break;
159 default:
160 printf("Structure: %02X (unknown)\n",
161 curfile_structure);
162 }
163 printf("File status: %02X\n", sim_resp_data[11]);
164 show_access_conditions("UPDATE", sim_resp_data[8] & 0xF);
165 show_access_conditions("READ & SEEK", sim_resp_data[8] >> 4);
166 show_access_conditions("INCREASE", sim_resp_data[9] >> 4);
167 show_access_conditions("INVALIDATE", sim_resp_data[10] & 0xF);
168 show_access_conditions("REHABILITATE", sim_resp_data[10] >> 4);
169 break;
170 default:
171 printf("File type: %02X (unknown)\n", sim_resp_data[6]);
172 }
173 return(0);
174 }
175
176 parse_ef_select_response()
177 {
178 if (sim_resp_data_len < 14) {
179 fprintf(stderr,
180 "error: SELECT response length of %u bytes is too short\n",
181 sim_resp_data_len);
182 return(-1);
183 }
184 if (sim_resp_data[6] != 0x04) {
185 fprintf(stderr, "error: selected file is not an EF\n");
186 return(-1);
187 }
188 curfile_total_size = (sim_resp_data[2] << 8) | sim_resp_data[3];
189 curfile_structure = sim_resp_data[13];
190 switch (curfile_structure) {
191 case 0x00:
192 /* transparent */
193 break;
194 case 0x01:
195 case 0x03:
196 /* record-based */
197 if (sim_resp_data_len < 15) {
198 fprintf(stderr,
199 "error: SELECT response length of %u bytes is too short for record-based EF\n",
200 sim_resp_data_len);
201 return(-1);
202 }
203 curfile_record_len = sim_resp_data[14];
204 if (!curfile_record_len) {
205 fprintf(stderr,
206 "error: SELECT response indicates record length of 0\n");
207 return(-1);
208 }
209 if (curfile_total_size % curfile_record_len) {
210 fprintf(stderr,
211 "error: returned file size is not divisible by record length\n");
212 return(-1);
213 }
214 curfile_record_count = curfile_total_size / curfile_record_len;
215 break;
216 default:
217 fprintf(stderr, "error: unknown EF structure code %02X\n",
218 curfile_structure);
219 return(-1);
220 }
221 return(0);
222 }