]>
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 | ||
78a4b8d2 | 54 | new_response = g_new(VCardResponse, 1); |
7267c094 | 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 | ||
78a4b8d2 | 135 | new_response = g_new(VCardResponse, 1); |
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 | ||
78a4b8d2 | 152 | new_response = g_new(VCardResponse, 1); |
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 = | |
4c293dc6 | 235 | (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPRIETARY; |
111a38b0 RR |
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 | ||
78a4b8d2 MT |
339 | new_apdu = g_new(VCardAPDU, 1); |
340 | new_apdu->a_data = g_memdup(raw_apdu, len); | |
111a38b0 RR |
341 | new_apdu->a_len = len; |
342 | *status = vcard_apdu_set_class(new_apdu); | |
343 | if (*status != VCARD7816_STATUS_SUCCESS) { | |
7267c094 | 344 | g_free(new_apdu); |
111a38b0 RR |
345 | return NULL; |
346 | } | |
347 | *status = vcard_apdu_set_length(new_apdu); | |
348 | if (*status != VCARD7816_STATUS_SUCCESS) { | |
7267c094 | 349 | g_free(new_apdu); |
111a38b0 RR |
350 | new_apdu = NULL; |
351 | } | |
352 | return new_apdu; | |
353 | } | |
354 | ||
355 | void | |
356 | vcard_apdu_delete(VCardAPDU *apdu) | |
357 | { | |
358 | if (apdu == NULL) { | |
359 | return; | |
360 | } | |
361 | if (apdu->a_data) { | |
7267c094 | 362 | g_free(apdu->a_data); |
111a38b0 | 363 | } |
7267c094 | 364 | g_free(apdu); |
111a38b0 RR |
365 | } |
366 | ||
367 | ||
368 | /* | |
369 | * declare response buffers for all the 7816 defined error codes | |
370 | */ | |
371 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS) | |
372 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING) | |
373 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT) | |
374 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE) | |
375 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED) | |
376 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID) | |
377 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE) | |
378 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED) | |
379 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR) | |
380 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE) | |
381 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE) | |
382 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH) | |
383 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED) | |
384 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED) | |
385 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED) | |
386 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED) | |
387 | VCARD_RESPONSE_NEW_STATIC_STATUS( | |
388 | VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE) | |
389 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED) | |
390 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED) | |
391 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID) | |
392 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED) | |
393 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF) | |
394 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING) | |
395 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT) | |
396 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS) | |
397 | VCARD_RESPONSE_NEW_STATIC_STATUS( | |
398 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA) | |
399 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED) | |
400 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND) | |
401 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND) | |
402 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE) | |
403 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT) | |
404 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT) | |
405 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT) | |
406 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND) | |
407 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2) | |
408 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID) | |
409 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID) | |
410 | VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL) | |
411 | ||
412 | /* | |
413 | * return a single response code. This function cannot fail. It will always | |
414 | * return a response. | |
415 | */ | |
416 | VCardResponse * | |
417 | vcard_make_response(vcard_7816_status_t status) | |
418 | { | |
1687a089 | 419 | VCardResponse *response; |
111a38b0 RR |
420 | |
421 | switch (status) { | |
422 | /* known 7816 response codes */ | |
423 | case VCARD7816_STATUS_SUCCESS: | |
424 | return VCARD_RESPONSE_GET_STATIC( | |
425 | VCARD7816_STATUS_SUCCESS); | |
426 | case VCARD7816_STATUS_WARNING: | |
427 | return VCARD_RESPONSE_GET_STATIC( | |
428 | VCARD7816_STATUS_WARNING); | |
429 | case VCARD7816_STATUS_WARNING_RET_CORUPT: | |
430 | return VCARD_RESPONSE_GET_STATIC( | |
431 | VCARD7816_STATUS_WARNING_RET_CORUPT); | |
432 | case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE: | |
433 | return VCARD_RESPONSE_GET_STATIC( | |
434 | VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE); | |
435 | case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED: | |
436 | return VCARD_RESPONSE_GET_STATIC( | |
437 | VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED); | |
438 | case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID: | |
439 | return VCARD_RESPONSE_GET_STATIC( | |
440 | VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID); | |
441 | case VCARD7816_STATUS_WARNING_CHANGE: | |
442 | return VCARD_RESPONSE_GET_STATIC( | |
443 | VCARD7816_STATUS_WARNING_CHANGE); | |
444 | case VCARD7816_STATUS_WARNING_FILE_FILLED: | |
445 | return VCARD_RESPONSE_GET_STATIC( | |
446 | VCARD7816_STATUS_WARNING_FILE_FILLED); | |
447 | case VCARD7816_STATUS_EXC_ERROR: | |
448 | return VCARD_RESPONSE_GET_STATIC( | |
449 | VCARD7816_STATUS_EXC_ERROR); | |
450 | case VCARD7816_STATUS_EXC_ERROR_CHANGE: | |
451 | return VCARD_RESPONSE_GET_STATIC( | |
452 | VCARD7816_STATUS_EXC_ERROR_CHANGE); | |
453 | case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE: | |
454 | return VCARD_RESPONSE_GET_STATIC( | |
455 | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
456 | case VCARD7816_STATUS_ERROR_WRONG_LENGTH: | |
457 | return VCARD_RESPONSE_GET_STATIC( | |
458 | VCARD7816_STATUS_ERROR_WRONG_LENGTH); | |
459 | case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED: | |
460 | return VCARD_RESPONSE_GET_STATIC( | |
461 | VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED); | |
462 | case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED: | |
463 | return VCARD_RESPONSE_GET_STATIC( | |
464 | VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED); | |
465 | case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED: | |
466 | return VCARD_RESPONSE_GET_STATIC( | |
467 | VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); | |
468 | case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED: | |
469 | return VCARD_RESPONSE_GET_STATIC( | |
470 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
471 | case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE: | |
472 | return VCARD_RESPONSE_GET_STATIC( | |
473 | VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE); | |
474 | case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED: | |
475 | return VCARD_RESPONSE_GET_STATIC( | |
476 | VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED); | |
477 | case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED: | |
478 | return VCARD_RESPONSE_GET_STATIC( | |
479 | VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED); | |
480 | case VCARD7816_STATUS_ERROR_DATA_INVALID: | |
481 | return VCARD_RESPONSE_GET_STATIC( | |
482 | VCARD7816_STATUS_ERROR_DATA_INVALID); | |
483 | case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED: | |
484 | return VCARD_RESPONSE_GET_STATIC( | |
485 | VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); | |
486 | case VCARD7816_STATUS_ERROR_DATA_NO_EF: | |
487 | return VCARD_RESPONSE_GET_STATIC( | |
488 | VCARD7816_STATUS_ERROR_DATA_NO_EF); | |
489 | case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING: | |
490 | return VCARD_RESPONSE_GET_STATIC( | |
491 | VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING); | |
492 | case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT: | |
493 | return VCARD_RESPONSE_GET_STATIC( | |
494 | VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT); | |
495 | case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS: | |
496 | return VCARD_RESPONSE_GET_STATIC( | |
497 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); | |
498 | case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA: | |
499 | return VCARD_RESPONSE_GET_STATIC( | |
500 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA); | |
501 | case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED: | |
502 | return VCARD_RESPONSE_GET_STATIC( | |
503 | VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); | |
504 | case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND: | |
505 | return VCARD_RESPONSE_GET_STATIC( | |
506 | VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); | |
507 | case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND: | |
508 | return VCARD_RESPONSE_GET_STATIC( | |
509 | VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND); | |
510 | case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE: | |
511 | return VCARD_RESPONSE_GET_STATIC( | |
512 | VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE); | |
513 | case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT: | |
514 | return VCARD_RESPONSE_GET_STATIC( | |
515 | VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT); | |
516 | case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT: | |
517 | return VCARD_RESPONSE_GET_STATIC( | |
518 | VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); | |
519 | case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT: | |
520 | return VCARD_RESPONSE_GET_STATIC( | |
521 | VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT); | |
522 | case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND: | |
523 | return VCARD_RESPONSE_GET_STATIC( | |
524 | VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); | |
525 | case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2: | |
526 | return VCARD_RESPONSE_GET_STATIC( | |
527 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2); | |
528 | case VCARD7816_STATUS_ERROR_INS_CODE_INVALID: | |
529 | return VCARD_RESPONSE_GET_STATIC( | |
530 | VCARD7816_STATUS_ERROR_INS_CODE_INVALID); | |
531 | case VCARD7816_STATUS_ERROR_CLA_INVALID: | |
532 | return VCARD_RESPONSE_GET_STATIC( | |
533 | VCARD7816_STATUS_ERROR_CLA_INVALID); | |
534 | case VCARD7816_STATUS_ERROR_GENERAL: | |
535 | return VCARD_RESPONSE_GET_STATIC( | |
536 | VCARD7816_STATUS_ERROR_GENERAL); | |
537 | default: | |
538 | /* we don't know this status code, create a response buffer to | |
539 | * hold it */ | |
540 | response = vcard_response_new_status(status); | |
541 | if (response == NULL) { | |
542 | /* couldn't allocate the buffer, return memmory error */ | |
543 | return VCARD_RESPONSE_GET_STATIC( | |
544 | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
545 | } | |
1687a089 | 546 | return response; |
111a38b0 | 547 | } |
111a38b0 RR |
548 | } |
549 | ||
550 | /* | |
551 | * Add File card support here if you need it. | |
552 | */ | |
553 | static VCardStatus | |
554 | vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu, | |
555 | VCardResponse **response) | |
556 | { | |
557 | /* TODO: if we want to support a virtual file system card, we do it here. | |
558 | * It would probably be a pkcs #15 card type */ | |
559 | *response = vcard_make_response( | |
560 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
561 | return VCARD_DONE; | |
562 | } | |
563 | ||
564 | /* | |
565 | * VM card (including java cards) | |
566 | */ | |
567 | static VCardStatus | |
568 | vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, | |
569 | VCardResponse **response) | |
570 | { | |
571 | int bytes_to_copy, next_byte_count, count; | |
572 | VCardApplet *current_applet; | |
573 | VCardBufferResponse *buffer_response; | |
574 | vcard_7816_status_t status; | |
575 | ||
576 | /* parse the class first */ | |
577 | if (apdu->a_gen_type != VCARD_7816_ISO) { | |
578 | *response = vcard_make_response( | |
579 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
580 | return VCARD_DONE; | |
581 | } | |
582 | ||
583 | /* use a switch so that if we need to support secure channel stuff later, | |
584 | * we know where to put it */ | |
585 | switch (apdu->a_secure_messaging) { | |
586 | case 0x0: /* no SM */ | |
587 | break; | |
588 | case 0x4: /* proprietary SM */ | |
589 | case 0x8: /* header not authenticated */ | |
590 | case 0xc: /* header authenticated */ | |
591 | default: | |
592 | /* for now, don't try to support secure channel stuff in the | |
593 | * virtual card. */ | |
594 | *response = vcard_make_response( | |
595 | VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); | |
596 | return VCARD_DONE; | |
597 | } | |
598 | ||
599 | /* now parse the instruction */ | |
600 | switch (apdu->a_ins) { | |
601 | case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */ | |
602 | case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */ | |
603 | case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */ | |
604 | case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */ | |
605 | case VCARD7816_INS_ERASE_BINARY: /* applet control op */ | |
606 | case VCARD7816_INS_READ_BINARY: /* applet control op */ | |
607 | case VCARD7816_INS_WRITE_BINARY: /* applet control op */ | |
608 | case VCARD7816_INS_UPDATE_BINARY: /* applet control op */ | |
609 | case VCARD7816_INS_READ_RECORD: /* file op */ | |
610 | case VCARD7816_INS_WRITE_RECORD: /* file op */ | |
611 | case VCARD7816_INS_UPDATE_RECORD: /* file op */ | |
612 | case VCARD7816_INS_APPEND_RECORD: /* file op */ | |
613 | case VCARD7816_INS_ENVELOPE: | |
614 | case VCARD7816_INS_PUT_DATA: | |
615 | *response = vcard_make_response( | |
616 | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
617 | break; | |
618 | ||
619 | case VCARD7816_INS_SELECT_FILE: | |
620 | if (apdu->a_p1 != 0x04) { | |
621 | *response = vcard_make_response( | |
622 | VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); | |
623 | break; | |
624 | } | |
625 | ||
626 | /* side effect, deselect the current applet if no applet has been found | |
627 | * */ | |
628 | current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); | |
629 | vcard_select_applet(card, apdu->a_channel, current_applet); | |
630 | if (current_applet) { | |
631 | unsigned char *aid; | |
632 | int aid_len; | |
633 | aid = vcard_applet_get_aid(current_applet, &aid_len); | |
634 | *response = vcard_response_new(card, aid, aid_len, apdu->a_Le, | |
635 | VCARD7816_STATUS_SUCCESS); | |
636 | } else { | |
637 | *response = vcard_make_response( | |
638 | VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); | |
639 | } | |
640 | break; | |
641 | ||
642 | case VCARD7816_INS_VERIFY: | |
643 | if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { | |
644 | *response = vcard_make_response( | |
645 | VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); | |
646 | } else { | |
647 | if (apdu->a_Lc == 0) { | |
648 | /* handle pin count if possible */ | |
649 | count = vcard_emul_get_login_count(card); | |
650 | if (count < 0) { | |
651 | *response = vcard_make_response( | |
652 | VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); | |
653 | } else { | |
654 | if (count > 0xf) { | |
655 | count = 0xf; | |
656 | } | |
657 | *response = vcard_response_new_status_bytes( | |
658 | VCARD7816_SW1_WARNING_CHANGE, | |
659 | 0xc0 | count); | |
660 | if (*response == NULL) { | |
661 | *response = vcard_make_response( | |
662 | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
663 | } | |
664 | } | |
665 | } else { | |
666 | status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc); | |
667 | *response = vcard_make_response(status); | |
668 | } | |
669 | } | |
670 | break; | |
671 | ||
672 | case VCARD7816_INS_GET_RESPONSE: | |
673 | buffer_response = vcard_get_buffer_response(card); | |
674 | if (!buffer_response) { | |
675 | *response = vcard_make_response( | |
676 | VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); | |
677 | /* handle error */ | |
678 | break; | |
679 | } | |
680 | bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); | |
681 | next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); | |
682 | *response = vcard_response_new_bytes( | |
683 | card, buffer_response->current, bytes_to_copy, | |
684 | apdu->a_Le, | |
685 | next_byte_count ? | |
686 | VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS, | |
687 | next_byte_count); | |
688 | buffer_response->current += bytes_to_copy; | |
689 | buffer_response->len -= bytes_to_copy; | |
690 | if (*response == NULL || (next_byte_count == 0)) { | |
691 | vcard_set_buffer_response(card, NULL); | |
692 | vcard_buffer_response_delete(buffer_response); | |
693 | } | |
694 | if (*response == NULL) { | |
695 | *response = | |
696 | vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); | |
697 | } | |
698 | break; | |
699 | ||
700 | case VCARD7816_INS_GET_DATA: | |
701 | *response = | |
702 | vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
703 | break; | |
704 | ||
705 | default: | |
706 | *response = | |
707 | vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
708 | break; | |
709 | } | |
710 | ||
711 | /* response should have been set somewhere */ | |
712 | assert(*response != NULL); | |
713 | return VCARD_DONE; | |
714 | } | |
715 | ||
716 | ||
717 | /* | |
718 | * APDU processing starts here. This routes the card processing stuff to the | |
719 | * right location. | |
720 | */ | |
721 | VCardStatus | |
722 | vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) | |
723 | { | |
724 | VCardStatus status; | |
725 | VCardBufferResponse *buffer_response; | |
726 | ||
727 | /* first handle any PTS commands, which aren't really APDU's */ | |
728 | if (apdu->a_type == VCARD_7816_PTS) { | |
729 | /* the PTS responses aren't really responses either */ | |
730 | *response = vcard_response_new_data(apdu->a_data, apdu->a_len); | |
731 | /* PTS responses have no status bytes */ | |
732 | (*response)->b_total_len = (*response)->b_len; | |
733 | return VCARD_DONE; | |
734 | } | |
735 | buffer_response = vcard_get_buffer_response(card); | |
736 | if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { | |
737 | /* clear out buffer_response, return an error */ | |
738 | vcard_set_buffer_response(card, NULL); | |
739 | vcard_buffer_response_delete(buffer_response); | |
740 | *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); | |
741 | return VCARD_DONE; | |
742 | } | |
743 | ||
744 | status = vcard_process_applet_apdu(card, apdu, response); | |
745 | if (status != VCARD_NEXT) { | |
746 | return status; | |
747 | } | |
748 | switch (vcard_get_type(card)) { | |
749 | case VCARD_FILE_SYSTEM: | |
750 | return vcard7816_file_system_process_apdu(card, apdu, response); | |
751 | case VCARD_VM: | |
752 | return vcard7816_vm_process_apdu(card, apdu, response); | |
753 | case VCARD_DIRECT: | |
754 | /* if we are type direct, then the applet should handle everything */ | |
d9676f82 | 755 | assert(!"VCARD_DIRECT: applet failure"); |
111a38b0 RR |
756 | break; |
757 | } | |
758 | *response = | |
759 | vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); | |
760 | return VCARD_DONE; | |
761 | } |