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