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