]>
Commit | Line | Data |
---|---|---|
111a38b0 RR |
1 | /* |
2 | * Implement the 7816 portion of the card spec | |
3 | * | |
4 | * This code is licensed under the GNU LGPL, version 2.1 or later. | |
5 | * See the COPYING.LIB file in the top-level directory. | |
6 | */ | |
7 | ||
8 | #include "qemu-common.h" | |
9 | ||
10 | #include "vcard.h" | |
11 | #include "vcard_emul.h" | |
12 | #include "card_7816.h" | |
13 | ||
14 | /* | |
15 | * set the status bytes based on the status word | |
16 | */ | |
17 | static void | |
18 | vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status) | |
19 | { | |
20 | unsigned char sw1, sw2; | |
21 | response->b_status = status; /* make sure the status and swX representations | |
22 | * are consistent */ | |
23 | sw1 = (status >> 8) & 0xff; | |
24 | sw2 = status & 0xff; | |
25 | response->b_sw1 = sw1; | |
26 | response->b_sw2 = sw2; | |
27 | response->b_data[response->b_len] = sw1; | |
28 | response->b_data[response->b_len+1] = sw2; | |
29 | } | |
30 | ||
31 | /* | |
32 | * set the status bytes in a response buffer | |
33 | */ | |
34 | static void | |
35 | vcard_response_set_status_bytes(VCardResponse *response, | |
36 | unsigned char sw1, unsigned char sw2) | |
37 | { | |
38 | response->b_status = sw1 << 8 | sw2; | |
39 | response->b_sw1 = sw1; | |
40 | response->b_sw2 = sw2; | |
41 | response->b_data[response->b_len] = sw1; | |
42 | response->b_data[response->b_len+1] = sw2; | |
43 | } | |
44 | ||
45 | /* | |
46 | * allocate a VCardResponse structure, plus space for the data buffer, and | |
47 | * set up everything but the resonse bytes. | |
48 | */ | |
49 | VCardResponse * | |
50 | vcard_response_new_data(unsigned char *buf, int len) | |
51 | { | |
52 | VCardResponse *new_response; | |
53 | ||
7267c094 AL |
54 | new_response = (VCardResponse *)g_malloc(sizeof(VCardResponse)); |
55 | new_response->b_data = g_malloc(len + 2); | |
111a38b0 RR |
56 | memcpy(new_response->b_data, buf, len); |
57 | new_response->b_total_len = len+2; | |
58 | new_response->b_len = len; | |
59 | new_response->b_type = VCARD_MALLOC; | |
60 | return new_response; | |
61 | } | |
62 | ||
63 | static VCardResponse * | |
64 | vcard_init_buffer_response(VCard *card, unsigned char *buf, int len) | |
65 | { | |
66 | VCardResponse *response; | |
67 | VCardBufferResponse *buffer_response; | |
68 | ||
69 | buffer_response = vcard_get_buffer_response(card); | |
70 | if (buffer_response) { | |
71 | vcard_set_buffer_response(card, NULL); | |
72 | vcard_buffer_response_delete(buffer_response); | |
73 | } | |
74 | buffer_response = vcard_buffer_response_new(buf, len); | |
75 | if (buffer_response == NULL) { | |
76 | return NULL; | |
77 | } | |
78 | response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, | |
79 | len > 255 ? 0 : len); | |
80 | if (response == NULL) { | |
81 | return NULL; | |
82 | } | |
83 | vcard_set_buffer_response(card, buffer_response); | |
84 | return response; | |
85 | } | |
86 | ||
87 | /* | |
88 | * general buffer to hold results from APDU calls | |
89 | */ | |
90 | VCardResponse * | |
91 | vcard_response_new(VCard *card, unsigned char *buf, | |
92 | int len, int Le, vcard_7816_status_t status) | |
93 | { | |
94 | VCardResponse *new_response; | |
95 | ||
96 | if (len > Le) { | |
97 | return vcard_init_buffer_response(card, buf, len); | |
98 | } | |
99 | new_response = vcard_response_new_data(buf, len); | |
100 | if (new_response == NULL) { | |
101 | return NULL; | |
102 | } | |
103 | vcard_response_set_status(new_response, status); | |
104 | return new_response; | |
105 | } | |
106 | ||
107 | /* | |
108 | * general buffer to hold results from APDU calls | |
109 | */ | |
110 | VCardResponse * | |
111 | vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, | |
112 | unsigned char sw1, unsigned char sw2) | |
113 | { | |
114 | VCardResponse *new_response; | |
115 | ||
116 | if (len > Le) { | |
117 | return vcard_init_buffer_response(card, buf, len); | |
118 | } | |
119 | new_response = vcard_response_new_data(buf, len); | |
120 | if (new_response == NULL) { | |
121 | return NULL; | |
122 | } | |
123 | vcard_response_set_status_bytes(new_response, sw1, sw2); | |
124 | return new_response; | |
125 | } | |
126 | ||
127 | /* | |
cba919da | 128 | * get a new Response buffer that only has a status. |
111a38b0 RR |
129 | */ |
130 | static VCardResponse * | |
131 | vcard_response_new_status(vcard_7816_status_t status) | |
132 | { | |
133 | VCardResponse *new_response; | |
134 | ||
7267c094 | 135 | new_response = (VCardResponse *)g_malloc(sizeof(VCardResponse)); |
111a38b0 RR |
136 | new_response->b_data = &new_response->b_sw1; |
137 | new_response->b_len = 0; | |
138 | new_response->b_total_len = 2; | |
139 | new_response->b_type = VCARD_MALLOC_STRUCT; | |
140 | vcard_response_set_status(new_response, status); | |
141 | return new_response; | |
142 | } | |
143 | ||
144 | /* | |
145 | * same as above, but specify the status as separate bytes | |
146 | */ | |
147 | VCardResponse * | |
148 | vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2) | |
149 | { | |
150 | VCardResponse *new_response; | |
151 | ||
7267c094 | 152 | new_response = (VCardResponse *)g_malloc(sizeof(VCardResponse)); |
111a38b0 RR |
153 | new_response->b_data = &new_response->b_sw1; |
154 | new_response->b_len = 0; | |
155 | new_response->b_total_len = 2; | |
156 | new_response->b_type = VCARD_MALLOC_STRUCT; | |
157 | vcard_response_set_status_bytes(new_response, sw1, sw2); | |
158 | return new_response; | |
159 | } | |
160 | ||
161 | ||
162 | /* | |
163 | * free the response buffer. The Buffer has a type to handle the buffer | |
164 | * allocated in other ways than through malloc. | |
165 | */ | |
166 | void | |
167 | vcard_response_delete(VCardResponse *response) | |
168 | { | |
169 | if (response == NULL) { | |
170 | return; | |
171 | } | |
172 | switch (response->b_type) { | |
173 | case VCARD_MALLOC: | |
174 | /* everything was malloc'ed */ | |
175 | if (response->b_data) { | |
7267c094 | 176 | g_free(response->b_data); |
111a38b0 | 177 | } |
7267c094 | 178 | g_free(response); |
111a38b0 RR |
179 | break; |
180 | case VCARD_MALLOC_DATA: | |
181 | /* only the data buffer was malloc'ed */ | |
182 | if (response->b_data) { | |
7267c094 | 183 | g_free(response->b_data); |
111a38b0 RR |
184 | } |
185 | break; | |
186 | case VCARD_MALLOC_STRUCT: | |
187 | /* only the structure was malloc'ed */ | |
7267c094 | 188 | g_free(response); |
111a38b0 RR |
189 | break; |
190 | case VCARD_STATIC: | |
191 | break; | |
192 | } | |
193 | } | |
194 | ||
195 | /* | |
196 | * decode the class bit and set our generic type field, channel, and | |
197 | * secure messaging values. | |
198 | */ | |
199 | static vcard_7816_status_t | |
200 | vcard_apdu_set_class(VCardAPDU *apdu) { | |
201 | apdu->a_channel = 0; | |
202 | apdu->a_secure_messaging = 0; | |
203 | apdu->a_type = apdu->a_cla & 0xf0; | |
204 | apdu->a_gen_type = VCARD_7816_ISO; | |
205 | ||
206 | /* parse the class tables 8 & 9 of the 7816-4 Part 4 spec */ | |
207 | switch (apdu->a_type) { | |
208 | /* we only support the basic types */ | |
209 | case 0x00: | |
210 | case 0x80: | |
211 | case 0x90: | |
212 | case 0xa0: | |
213 | apdu->a_channel = apdu->a_cla & 3; | |
214 | apdu->a_secure_messaging = apdu->a_cla & 0xe; | |
215 | break; | |
216 | case 0xb0: | |
217 | case 0xc0: | |
218 | break; | |
219 | ||
220 | case 0x10: | |
221 | case 0x20: | |
222 | case 0x30: | |
223 | case 0x40: | |
224 | case 0x50: | |
225 | case 0x60: | |
226 | case 0x70: | |
227 | /* Reserved for future use */ | |
228 | apdu->a_gen_type = VCARD_7816_RFU; | |
229 | break; | |
230 | case 0xd0: | |
231 | case 0xe0: | |
232 | case 0xf0: | |
233 | default: | |
234 | apdu->a_gen_type = | |
235 | (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPIETARY; | |
236 | break; | |
237 | } | |
238 | return VCARD7816_STATUS_SUCCESS; | |
239 | } | |
240 | ||
241 | /* | |
cba919da | 242 | * set the Le and Lc fields according to table 5 of the |
111a38b0 RR |
243 | * 7816-4 part 4 spec |
244 | */ | |
245 | static vcard_7816_status_t | |
246 | vcard_apdu_set_length(VCardAPDU *apdu) | |
247 | { | |
248 | int L, Le; | |
249 | ||
250 | /* process according to table 5 of the 7816-4 Part 4 spec. | |
251 | * variable names match the variables in the spec */ | |
252 | L = apdu->a_len-4; /* fixed APDU header */ | |
253 | apdu->a_Lc = 0; | |
254 | apdu->a_Le = 0; | |
255 | apdu->a_body = NULL; | |
256 | switch (L) { | |
257 | case 0: | |
258 | /* 1 minimal apdu */ | |
259 | return VCARD7816_STATUS_SUCCESS; | |
260 | case 1: | |
261 | /* 2S only return values apdu */ | |
262 | /* zero maps to 256 here */ | |
263 | apdu->a_Le = apdu->a_header->ah_Le ? | |
264 | apdu->a_header->ah_Le : 256; | |
265 | return VCARD7816_STATUS_SUCCESS; | |
266 | default: | |
267 | /* if the ah_Le byte is zero and we have more than | |
268 | * 1 byte in the header, then we must be using extended Le and Lc. | |
269 | * process the extended now. */ | |
270 | if (apdu->a_header->ah_Le == 0) { | |
271 | if (L < 3) { | |
272 | /* coding error, need at least 3 bytes */ | |
273 | return VCARD7816_STATUS_ERROR_WRONG_LENGTH; | |
274 | } | |
275 | /* calculate the first extended value. Could be either Le or Lc */ | |
276 | Le = (apdu->a_header->ah_body[0] << 8) | |
277 | || apdu->a_header->ah_body[1]; | |
278 | if (L == 3) { | |
279 | /* 2E extended, return data only */ | |
280 | /* zero maps to 65536 */ | |
281 | apdu->a_Le = Le ? Le : 65536; | |
282 | return VCARD7816_STATUS_SUCCESS; | |
283 | } | |
284 | if (Le == 0) { | |
285 | /* reserved for future use, probably for next time we need | |
286 | * to extend the lengths */ | |
287 | return VCARD7816_STATUS_ERROR_WRONG_LENGTH; | |
288 | } | |
289 | /* we know that the first extended value is Lc now */ | |
290 | apdu->a_Lc = Le; | |
291 | apdu->a_body = &apdu->a_header->ah_body[2]; | |
292 | if (L == Le+3) { | |
293 | /* 3E extended, only body parameters */ | |
294 | return VCARD7816_STATUS_SUCCESS; | |
295 | } | |
296 | if (L == Le+5) { | |
297 | /* 4E extended, parameters and return data */ | |
298 | Le = (apdu->a_data[apdu->a_len-2] << 8) | |
299 | || apdu->a_data[apdu->a_len-1]; | |
300 | apdu->a_Le = Le ? Le : 65536; | |
301 | return VCARD7816_STATUS_SUCCESS; | |
302 | } | |
303 | return VCARD7816_STATUS_ERROR_WRONG_LENGTH; | |
304 | } | |
305 | /* not extended */ | |
306 | apdu->a_Lc = apdu->a_header->ah_Le; | |
307 | apdu->a_body = &apdu->a_header->ah_body[0]; | |
308 | if (L == apdu->a_Lc + 1) { | |
309 | /* 3S only body parameters */ | |
310 | return VCARD7816_STATUS_SUCCESS; | |
311 | } | |
312 | if (L == apdu->a_Lc + 2) { | |
313 | /* 4S parameters and return data */ | |
314 | Le = apdu->a_data[apdu->a_len-1]; | |
315 | apdu->a_Le = Le ? Le : 256; | |
316 | return VCARD7816_STATUS_SUCCESS; | |
317 | } | |
318 | break; | |
319 | } | |
320 | return VCARD7816_STATUS_ERROR_WRONG_LENGTH; | |
321 | } | |
322 | ||
323 | /* | |
324 | * create a new APDU from a raw set of bytes. This will decode all the | |
325 | * above fields. users of VCARDAPDU's can then depend on the already decoded | |
326 | * values. | |
327 | */ | |
328 | VCardAPDU * | |
329 | vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status) | |
330 | { | |
331 | VCardAPDU *new_apdu; | |
332 | ||
333 | *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; | |
334 | if (len < 4) { | |
335 | *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH; | |
336 | return NULL; | |
337 | } | |
338 | ||
7267c094 AL |
339 | new_apdu = (VCardAPDU *)g_malloc(sizeof(VCardAPDU)); |
340 | new_apdu->a_data = g_malloc(len); | |
111a38b0 RR |
341 | memcpy(new_apdu->a_data, raw_apdu, len); |
342 | new_apdu->a_len = len; | |
343 | *status = vcard_apdu_set_class(new_apdu); | |
344 | if (*status != VCARD7816_STATUS_SUCCESS) { | |
7267c094 | 345 | g_free(new_apdu); |
111a38b0 RR |
346 | return NULL; |
347 | } | |
348 | *status = vcard_apdu_set_length(new_apdu); | |
349 | if (*status != VCARD7816_STATUS_SUCCESS) { | |
7267c094 | 350 | g_free(new_apdu); |
111a38b0 RR |
351 | new_apdu = NULL; |
352 | } | |
353 | return new_apdu; | |
354 | } | |
355 | ||
356 | void | |
357 | vcard_apdu_delete(VCardAPDU *apdu) | |
358 | { | |
359 | if (apdu == NULL) { | |
360 | return; | |
361 | } | |
362 | if (apdu->a_data) { | |
7267c094 | 363 | g_free(apdu->a_data); |
111a38b0 | 364 | } |
7267c094 | 365 | g_free(apdu); |
111a38b0 RR |
366 | } |
367 | ||
368 | ||
369 | /* | |
370 | * declare response buffers for all the 7816 defined error codes | |
371 | */ | |
372 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS) | |
373 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING) | |
374 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT) | |
375 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE) | |
376 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED) | |
377 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID) | |
378 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE) | |
379 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED) | |
380 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR) | |
381 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE) | |
382 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE) | |
383 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH) | |
384 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED) | |
385 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED) | |
386 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED) | |
387 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED) | |
388 | VCARD_RESPONSE_NEW_STATIC_STATUS( | |
389 | VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE) | |
390 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED) | |
391 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED) | |
392 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID) | |
393 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED) | |
394 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF) | |
395 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING) | |
396 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT) | |
397 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS) | |
398 | VCARD_RESPONSE_NEW_STATIC_STATUS( | |
399 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA) | |
400 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED) | |
401 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND) | |
402 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND) | |
403 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE) | |
404 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT) | |
405 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT) | |
406 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT) | |
407 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND) | |
408 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2) | |
409 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID) | |
410 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID) | |
411 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL) | |
412 | ||
413 | /* | |
414 | * return a single response code. This function cannot fail. It will always | |
415 | * return a response. | |
416 | */ | |
417 | VCardResponse * | |
418 | vcard_make_response(vcard_7816_status_t status) | |
419 | { | |
420 | VCardResponse *response = NULL; | |
421 | ||
422 | switch (status) { | |
423 | /* known 7816 response codes */ | |
424 | case VCARD7816_STATUS_SUCCESS: | |
425 | return VCARD_RESPONSE_GET_STATIC( | |
426 | VCARD7816_STATUS_SUCCESS); | |
427 | case VCARD7816_STATUS_WARNING: | |
428 | return VCARD_RESPONSE_GET_STATIC( | |
429 | VCARD7816_STATUS_WARNING); | |
430 | case VCARD7816_STATUS_WARNING_RET_CORUPT: | |
431 | return VCARD_RESPONSE_GET_STATIC( | |
432 | VCARD7816_STATUS_WARNING_RET_CORUPT); | |
433 | case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE: | |
434 | return VCARD_RESPONSE_GET_STATIC( | |
435 | VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE); | |
436 | case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED: | |
437 | return VCARD_RESPONSE_GET_STATIC( | |
438 | VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED); | |
439 | case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID: | |
440 | return VCARD_RESPONSE_GET_STATIC( | |
441 | VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID); | |
442 | case VCARD7816_STATUS_WARNING_CHANGE: | |
443 | return VCARD_RESPONSE_GET_STATIC( | |
444 | VCARD7816_STATUS_WARNING_CHANGE); | |
445 | case VCARD7816_STATUS_WARNING_FILE_FILLED: | |
446 | return VCARD_RESPONSE_GET_STATIC( | |
447 | VCARD7816_STATUS_WARNING_FILE_FILLED); | |
448 | case VCARD7816_STATUS_EXC_ERROR: | |
449 | return VCARD_RESPONSE_GET_STATIC( | |
450 | VCARD7816_STATUS_EXC_ERROR); | |
451 | case VCARD7816_STATUS_EXC_ERROR_CHANGE: | |
452 | return VCARD_RESPONSE_GET_STATIC( | |
453 | VCARD7816_STATUS_EXC_ERROR_CHANGE); | |
454 | case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE: | |
455 | return VCARD_RESPONSE_GET_STATIC( | |
456 | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
457 | case VCARD7816_STATUS_ERROR_WRONG_LENGTH: | |
458 | return VCARD_RESPONSE_GET_STATIC( | |
459 | VCARD7816_STATUS_ERROR_WRONG_LENGTH); | |
460 | case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED: | |
461 | return VCARD_RESPONSE_GET_STATIC( | |
462 | VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED); | |
463 | case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED: | |
464 | return VCARD_RESPONSE_GET_STATIC( | |
465 | VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED); | |
466 | case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED: | |
467 | return VCARD_RESPONSE_GET_STATIC( | |
468 | VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); | |
469 | case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED: | |
470 | return VCARD_RESPONSE_GET_STATIC( | |
471 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
472 | case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE: | |
473 | return VCARD_RESPONSE_GET_STATIC( | |
474 | VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE); | |
475 | case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED: | |
476 | return VCARD_RESPONSE_GET_STATIC( | |
477 | VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED); | |
478 | case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED: | |
479 | return VCARD_RESPONSE_GET_STATIC( | |
480 | VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED); | |
481 | case VCARD7816_STATUS_ERROR_DATA_INVALID: | |
482 | return VCARD_RESPONSE_GET_STATIC( | |
483 | VCARD7816_STATUS_ERROR_DATA_INVALID); | |
484 | case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED: | |
485 | return VCARD_RESPONSE_GET_STATIC( | |
486 | VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); | |
487 | case VCARD7816_STATUS_ERROR_DATA_NO_EF: | |
488 | return VCARD_RESPONSE_GET_STATIC( | |
489 | VCARD7816_STATUS_ERROR_DATA_NO_EF); | |
490 | case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING: | |
491 | return VCARD_RESPONSE_GET_STATIC( | |
492 | VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING); | |
493 | case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT: | |
494 | return VCARD_RESPONSE_GET_STATIC( | |
495 | VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT); | |
496 | case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS: | |
497 | return VCARD_RESPONSE_GET_STATIC( | |
498 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); | |
499 | case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA: | |
500 | return VCARD_RESPONSE_GET_STATIC( | |
501 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA); | |
502 | case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED: | |
503 | return VCARD_RESPONSE_GET_STATIC( | |
504 | VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); | |
505 | case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND: | |
506 | return VCARD_RESPONSE_GET_STATIC( | |
507 | VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); | |
508 | case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND: | |
509 | return VCARD_RESPONSE_GET_STATIC( | |
510 | VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND); | |
511 | case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE: | |
512 | return VCARD_RESPONSE_GET_STATIC( | |
513 | VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE); | |
514 | case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT: | |
515 | return VCARD_RESPONSE_GET_STATIC( | |
516 | VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT); | |
517 | case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT: | |
518 | return VCARD_RESPONSE_GET_STATIC( | |
519 | VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); | |
520 | case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT: | |
521 | return VCARD_RESPONSE_GET_STATIC( | |
522 | VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT); | |
523 | case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND: | |
524 | return VCARD_RESPONSE_GET_STATIC( | |
525 | VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); | |
526 | case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2: | |
527 | return VCARD_RESPONSE_GET_STATIC( | |
528 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2); | |
529 | case VCARD7816_STATUS_ERROR_INS_CODE_INVALID: | |
530 | return VCARD_RESPONSE_GET_STATIC( | |
531 | VCARD7816_STATUS_ERROR_INS_CODE_INVALID); | |
532 | case VCARD7816_STATUS_ERROR_CLA_INVALID: | |
533 | return VCARD_RESPONSE_GET_STATIC( | |
534 | VCARD7816_STATUS_ERROR_CLA_INVALID); | |
535 | case VCARD7816_STATUS_ERROR_GENERAL: | |
536 | return VCARD_RESPONSE_GET_STATIC( | |
537 | VCARD7816_STATUS_ERROR_GENERAL); | |
538 | default: | |
539 | /* we don't know this status code, create a response buffer to | |
540 | * hold it */ | |
541 | response = vcard_response_new_status(status); | |
542 | if (response == NULL) { | |
543 | /* couldn't allocate the buffer, return memmory error */ | |
544 | return VCARD_RESPONSE_GET_STATIC( | |
545 | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
546 | } | |
547 | } | |
548 | assert(response); | |
549 | return response; | |
550 | } | |
551 | ||
552 | /* | |
553 | * Add File card support here if you need it. | |
554 | */ | |
555 | static VCardStatus | |
556 | vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu, | |
557 | VCardResponse **response) | |
558 | { | |
559 | /* TODO: if we want to support a virtual file system card, we do it here. | |
560 | * It would probably be a pkcs #15 card type */ | |
561 | *response = vcard_make_response( | |
562 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
563 | return VCARD_DONE; | |
564 | } | |
565 | ||
566 | /* | |
567 | * VM card (including java cards) | |
568 | */ | |
569 | static VCardStatus | |
570 | vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, | |
571 | VCardResponse **response) | |
572 | { | |
573 | int bytes_to_copy, next_byte_count, count; | |
574 | VCardApplet *current_applet; | |
575 | VCardBufferResponse *buffer_response; | |
576 | vcard_7816_status_t status; | |
577 | ||
578 | /* parse the class first */ | |
579 | if (apdu->a_gen_type != VCARD_7816_ISO) { | |
580 | *response = vcard_make_response( | |
581 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
582 | return VCARD_DONE; | |
583 | } | |
584 | ||
585 | /* use a switch so that if we need to support secure channel stuff later, | |
586 | * we know where to put it */ | |
587 | switch (apdu->a_secure_messaging) { | |
588 | case 0x0: /* no SM */ | |
589 | break; | |
590 | case 0x4: /* proprietary SM */ | |
591 | case 0x8: /* header not authenticated */ | |
592 | case 0xc: /* header authenticated */ | |
593 | default: | |
594 | /* for now, don't try to support secure channel stuff in the | |
595 | * virtual card. */ | |
596 | *response = vcard_make_response( | |
597 | VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); | |
598 | return VCARD_DONE; | |
599 | } | |
600 | ||
601 | /* now parse the instruction */ | |
602 | switch (apdu->a_ins) { | |
603 | case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */ | |
604 | case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */ | |
605 | case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */ | |
606 | case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */ | |
607 | case VCARD7816_INS_ERASE_BINARY: /* applet control op */ | |
608 | case VCARD7816_INS_READ_BINARY: /* applet control op */ | |
609 | case VCARD7816_INS_WRITE_BINARY: /* applet control op */ | |
610 | case VCARD7816_INS_UPDATE_BINARY: /* applet control op */ | |
611 | case VCARD7816_INS_READ_RECORD: /* file op */ | |
612 | case VCARD7816_INS_WRITE_RECORD: /* file op */ | |
613 | case VCARD7816_INS_UPDATE_RECORD: /* file op */ | |
614 | case VCARD7816_INS_APPEND_RECORD: /* file op */ | |
615 | case VCARD7816_INS_ENVELOPE: | |
616 | case VCARD7816_INS_PUT_DATA: | |
617 | *response = vcard_make_response( | |
618 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
619 | break; | |
620 | ||
621 | case VCARD7816_INS_SELECT_FILE: | |
622 | if (apdu->a_p1 != 0x04) { | |
623 | *response = vcard_make_response( | |
624 | VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); | |
625 | break; | |
626 | } | |
627 | ||
628 | /* side effect, deselect the current applet if no applet has been found | |
629 | * */ | |
630 | current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); | |
631 | vcard_select_applet(card, apdu->a_channel, current_applet); | |
632 | if (current_applet) { | |
633 | unsigned char *aid; | |
634 | int aid_len; | |
635 | aid = vcard_applet_get_aid(current_applet, &aid_len); | |
636 | *response = vcard_response_new(card, aid, aid_len, apdu->a_Le, | |
637 | VCARD7816_STATUS_SUCCESS); | |
638 | } else { | |
639 | *response = vcard_make_response( | |
640 | VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); | |
641 | } | |
642 | break; | |
643 | ||
644 | case VCARD7816_INS_VERIFY: | |
645 | if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { | |
646 | *response = vcard_make_response( | |
647 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); | |
648 | } else { | |
649 | if (apdu->a_Lc == 0) { | |
650 | /* handle pin count if possible */ | |
651 | count = vcard_emul_get_login_count(card); | |
652 | if (count < 0) { | |
653 | *response = vcard_make_response( | |
654 | VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); | |
655 | } else { | |
656 | if (count > 0xf) { | |
657 | count = 0xf; | |
658 | } | |
659 | *response = vcard_response_new_status_bytes( | |
660 | VCARD7816_SW1_WARNING_CHANGE, | |
661 | 0xc0 | count); | |
662 | if (*response == NULL) { | |
663 | *response = vcard_make_response( | |
664 | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
665 | } | |
666 | } | |
667 | } else { | |
668 | status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc); | |
669 | *response = vcard_make_response(status); | |
670 | } | |
671 | } | |
672 | break; | |
673 | ||
674 | case VCARD7816_INS_GET_RESPONSE: | |
675 | buffer_response = vcard_get_buffer_response(card); | |
676 | if (!buffer_response) { | |
677 | *response = vcard_make_response( | |
678 | VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); | |
679 | /* handle error */ | |
680 | break; | |
681 | } | |
682 | bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); | |
683 | next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); | |
684 | *response = vcard_response_new_bytes( | |
685 | card, buffer_response->current, bytes_to_copy, | |
686 | apdu->a_Le, | |
687 | next_byte_count ? | |
688 | VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS, | |
689 | next_byte_count); | |
690 | buffer_response->current += bytes_to_copy; | |
691 | buffer_response->len -= bytes_to_copy; | |
692 | if (*response == NULL || (next_byte_count == 0)) { | |
693 | vcard_set_buffer_response(card, NULL); | |
694 | vcard_buffer_response_delete(buffer_response); | |
695 | } | |
696 | if (*response == NULL) { | |
697 | *response = | |
698 | vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
699 | } | |
700 | break; | |
701 | ||
702 | case VCARD7816_INS_GET_DATA: | |
703 | *response = | |
704 | vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
705 | break; | |
706 | ||
707 | default: | |
708 | *response = | |
709 | vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
710 | break; | |
711 | } | |
712 | ||
713 | /* response should have been set somewhere */ | |
714 | assert(*response != NULL); | |
715 | return VCARD_DONE; | |
716 | } | |
717 | ||
718 | ||
719 | /* | |
720 | * APDU processing starts here. This routes the card processing stuff to the | |
721 | * right location. | |
722 | */ | |
723 | VCardStatus | |
724 | vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) | |
725 | { | |
726 | VCardStatus status; | |
727 | VCardBufferResponse *buffer_response; | |
728 | ||
729 | /* first handle any PTS commands, which aren't really APDU's */ | |
730 | if (apdu->a_type == VCARD_7816_PTS) { | |
731 | /* the PTS responses aren't really responses either */ | |
732 | *response = vcard_response_new_data(apdu->a_data, apdu->a_len); | |
733 | /* PTS responses have no status bytes */ | |
734 | (*response)->b_total_len = (*response)->b_len; | |
735 | return VCARD_DONE; | |
736 | } | |
737 | buffer_response = vcard_get_buffer_response(card); | |
738 | if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { | |
739 | /* clear out buffer_response, return an error */ | |
740 | vcard_set_buffer_response(card, NULL); | |
741 | vcard_buffer_response_delete(buffer_response); | |
742 | *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); | |
743 | return VCARD_DONE; | |
744 | } | |
745 | ||
746 | status = vcard_process_applet_apdu(card, apdu, response); | |
747 | if (status != VCARD_NEXT) { | |
748 | return status; | |
749 | } | |
750 | switch (vcard_get_type(card)) { | |
751 | case VCARD_FILE_SYSTEM: | |
752 | return vcard7816_file_system_process_apdu(card, apdu, response); | |
753 | case VCARD_VM: | |
754 | return vcard7816_vm_process_apdu(card, apdu, response); | |
755 | case VCARD_DIRECT: | |
756 | /* if we are type direct, then the applet should handle everything */ | |
d9676f82 | 757 | assert(!"VCARD_DIRECT: applet failure"); |
111a38b0 RR |
758 | break; |
759 | } | |
760 | *response = | |
761 | vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
762 | return VCARD_DONE; | |
763 | } |