/* * Implement the 7816 portion of the card spec * * This code is licensed under the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. */ #include "qemu-common.h" #include "vcard.h" #include "vcard_emul.h" #include "card_7816.h" /* * set the status bytes based on the status word */ static void vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status) { unsigned char sw1, sw2; response->b_status = status; /* make sure the status and swX representations * are consistent */ sw1 = (status >> 8) & 0xff; sw2 = status & 0xff; response->b_sw1 = sw1; response->b_sw2 = sw2; response->b_data[response->b_len] = sw1; response->b_data[response->b_len+1] = sw2; } /* * set the status bytes in a response buffer */ static void vcard_response_set_status_bytes(VCardResponse *response, unsigned char sw1, unsigned char sw2) { response->b_status = sw1 << 8 | sw2; response->b_sw1 = sw1; response->b_sw2 = sw2; response->b_data[response->b_len] = sw1; response->b_data[response->b_len+1] = sw2; } /* * allocate a VCardResponse structure, plus space for the data buffer, and * set up everything but the resonse bytes. */ VCardResponse * vcard_response_new_data(unsigned char *buf, int len) { VCardResponse *new_response; new_response = g_new(VCardResponse, 1); new_response->b_data = g_malloc(len + 2); memcpy(new_response->b_data, buf, len); new_response->b_total_len = len+2; new_response->b_len = len; new_response->b_type = VCARD_MALLOC; return new_response; } static VCardResponse * vcard_init_buffer_response(VCard *card, unsigned char *buf, int len) { VCardResponse *response; VCardBufferResponse *buffer_response; buffer_response = vcard_get_buffer_response(card); if (buffer_response) { vcard_set_buffer_response(card, NULL); vcard_buffer_response_delete(buffer_response); } buffer_response = vcard_buffer_response_new(buf, len); if (buffer_response == NULL) { return NULL; } response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, len > 255 ? 0 : len); if (response == NULL) { return NULL; } vcard_set_buffer_response(card, buffer_response); return response; } /* * general buffer to hold results from APDU calls */ VCardResponse * vcard_response_new(VCard *card, unsigned char *buf, int len, int Le, vcard_7816_status_t status) { VCardResponse *new_response; if (len > Le) { return vcard_init_buffer_response(card, buf, len); } new_response = vcard_response_new_data(buf, len); if (new_response == NULL) { return NULL; } vcard_response_set_status(new_response, status); return new_response; } /* * general buffer to hold results from APDU calls */ VCardResponse * vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, unsigned char sw1, unsigned char sw2) { VCardResponse *new_response; if (len > Le) { return vcard_init_buffer_response(card, buf, len); } new_response = vcard_response_new_data(buf, len); if (new_response == NULL) { return NULL; } vcard_response_set_status_bytes(new_response, sw1, sw2); return new_response; } /* * get a new Response buffer that only has a status. */ static VCardResponse * vcard_response_new_status(vcard_7816_status_t status) { VCardResponse *new_response; new_response = g_new(VCardResponse, 1); new_response->b_data = &new_response->b_sw1; new_response->b_len = 0; new_response->b_total_len = 2; new_response->b_type = VCARD_MALLOC_STRUCT; vcard_response_set_status(new_response, status); return new_response; } /* * same as above, but specify the status as separate bytes */ VCardResponse * vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2) { VCardResponse *new_response; new_response = g_new(VCardResponse, 1); new_response->b_data = &new_response->b_sw1; new_response->b_len = 0; new_response->b_total_len = 2; new_response->b_type = VCARD_MALLOC_STRUCT; vcard_response_set_status_bytes(new_response, sw1, sw2); return new_response; } /* * free the response buffer. The Buffer has a type to handle the buffer * allocated in other ways than through malloc. */ void vcard_response_delete(VCardResponse *response) { if (response == NULL) { return; } switch (response->b_type) { case VCARD_MALLOC: /* everything was malloc'ed */ if (response->b_data) { g_free(response->b_data); } g_free(response); break; case VCARD_MALLOC_DATA: /* only the data buffer was malloc'ed */ if (response->b_data) { g_free(response->b_data); } break; case VCARD_MALLOC_STRUCT: /* only the structure was malloc'ed */ g_free(response); break; case VCARD_STATIC: break; } } /* * decode the class bit and set our generic type field, channel, and * secure messaging values. */ static vcard_7816_status_t vcard_apdu_set_class(VCardAPDU *apdu) { apdu->a_channel = 0; apdu->a_secure_messaging = 0; apdu->a_type = apdu->a_cla & 0xf0; apdu->a_gen_type = VCARD_7816_ISO; /* parse the class tables 8 & 9 of the 7816-4 Part 4 spec */ switch (apdu->a_type) { /* we only support the basic types */ case 0x00: case 0x80: case 0x90: case 0xa0: apdu->a_channel = apdu->a_cla & 3; apdu->a_secure_messaging = apdu->a_cla & 0xe; break; case 0xb0: case 0xc0: break; case 0x10: case 0x20: case 0x30: case 0x40: case 0x50: case 0x60: case 0x70: /* Reserved for future use */ apdu->a_gen_type = VCARD_7816_RFU; break; case 0xd0: case 0xe0: case 0xf0: default: apdu->a_gen_type = (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPRIETARY; break; } return VCARD7816_STATUS_SUCCESS; } /* * set the Le and Lc fields according to table 5 of the * 7816-4 part 4 spec */ static vcard_7816_status_t vcard_apdu_set_length(VCardAPDU *apdu) { int L, Le; /* process according to table 5 of the 7816-4 Part 4 spec. * variable names match the variables in the spec */ L = apdu->a_len-4; /* fixed APDU header */ apdu->a_Lc = 0; apdu->a_Le = 0; apdu->a_body = NULL; switch (L) { case 0: /* 1 minimal apdu */ return VCARD7816_STATUS_SUCCESS; case 1: /* 2S only return values apdu */ /* zero maps to 256 here */ apdu->a_Le = apdu->a_header->ah_Le ? apdu->a_header->ah_Le : 256; return VCARD7816_STATUS_SUCCESS; default: /* if the ah_Le byte is zero and we have more than * 1 byte in the header, then we must be using extended Le and Lc. * process the extended now. */ if (apdu->a_header->ah_Le == 0) { if (L < 3) { /* coding error, need at least 3 bytes */ return VCARD7816_STATUS_ERROR_WRONG_LENGTH; } /* calculate the first extended value. Could be either Le or Lc */ Le = (apdu->a_header->ah_body[0] << 8) || apdu->a_header->ah_body[1]; if (L == 3) { /* 2E extended, return data only */ /* zero maps to 65536 */ apdu->a_Le = Le ? Le : 65536; return VCARD7816_STATUS_SUCCESS; } if (Le == 0) { /* reserved for future use, probably for next time we need * to extend the lengths */ return VCARD7816_STATUS_ERROR_WRONG_LENGTH; } /* we know that the first extended value is Lc now */ apdu->a_Lc = Le; apdu->a_body = &apdu->a_header->ah_body[2]; if (L == Le+3) { /* 3E extended, only body parameters */ return VCARD7816_STATUS_SUCCESS; } if (L == Le+5) { /* 4E extended, parameters and return data */ Le = (apdu->a_data[apdu->a_len-2] << 8) || apdu->a_data[apdu->a_len-1]; apdu->a_Le = Le ? Le : 65536; return VCARD7816_STATUS_SUCCESS; } return VCARD7816_STATUS_ERROR_WRONG_LENGTH; } /* not extended */ apdu->a_Lc = apdu->a_header->ah_Le; apdu->a_body = &apdu->a_header->ah_body[0]; if (L == apdu->a_Lc + 1) { /* 3S only body parameters */ return VCARD7816_STATUS_SUCCESS; } if (L == apdu->a_Lc + 2) { /* 4S parameters and return data */ Le = apdu->a_data[apdu->a_len-1]; apdu->a_Le = Le ? Le : 256; return VCARD7816_STATUS_SUCCESS; } break; } return VCARD7816_STATUS_ERROR_WRONG_LENGTH; } /* * create a new APDU from a raw set of bytes. This will decode all the * above fields. users of VCARDAPDU's can then depend on the already decoded * values. */ VCardAPDU * vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status) { VCardAPDU *new_apdu; *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; if (len < 4) { *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH; return NULL; } new_apdu = g_new(VCardAPDU, 1); new_apdu->a_data = g_memdup(raw_apdu, len); new_apdu->a_len = len; *status = vcard_apdu_set_class(new_apdu); if (*status != VCARD7816_STATUS_SUCCESS) { g_free(new_apdu); return NULL; } *status = vcard_apdu_set_length(new_apdu); if (*status != VCARD7816_STATUS_SUCCESS) { g_free(new_apdu); new_apdu = NULL; } return new_apdu; } void vcard_apdu_delete(VCardAPDU *apdu) { if (apdu == NULL) { return; } if (apdu->a_data) { g_free(apdu->a_data); } g_free(apdu); } /* * declare response buffers for all the 7816 defined error codes */ VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED) VCARD_RESPONSE_NEW_STATIC_STATUS( VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS) VCARD_RESPONSE_NEW_STATIC_STATUS( VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID) VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL) /* * return a single response code. This function cannot fail. It will always * return a response. */ VCardResponse * vcard_make_response(vcard_7816_status_t status) { VCardResponse *response = NULL; switch (status) { /* known 7816 response codes */ case VCARD7816_STATUS_SUCCESS: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_SUCCESS); case VCARD7816_STATUS_WARNING: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING); case VCARD7816_STATUS_WARNING_RET_CORUPT: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING_RET_CORUPT); case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE); case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED); case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID); case VCARD7816_STATUS_WARNING_CHANGE: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING_CHANGE); case VCARD7816_STATUS_WARNING_FILE_FILLED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_WARNING_FILE_FILLED); case VCARD7816_STATUS_EXC_ERROR: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_EXC_ERROR); case VCARD7816_STATUS_EXC_ERROR_CHANGE: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_EXC_ERROR_CHANGE); case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); case VCARD7816_STATUS_ERROR_WRONG_LENGTH: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_WRONG_LENGTH); case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED); case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED); case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE); case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED); case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED); case VCARD7816_STATUS_ERROR_DATA_INVALID: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_DATA_INVALID); case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); case VCARD7816_STATUS_ERROR_DATA_NO_EF: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_DATA_NO_EF); case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING); case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT); case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA); case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND); case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE); case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT); case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT); case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2); case VCARD7816_STATUS_ERROR_INS_CODE_INVALID: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_INS_CODE_INVALID); case VCARD7816_STATUS_ERROR_CLA_INVALID: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_CLA_INVALID); case VCARD7816_STATUS_ERROR_GENERAL: return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_ERROR_GENERAL); default: /* we don't know this status code, create a response buffer to * hold it */ response = vcard_response_new_status(status); if (response == NULL) { /* couldn't allocate the buffer, return memmory error */ return VCARD_RESPONSE_GET_STATIC( VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); } } assert(response); return response; } /* * Add File card support here if you need it. */ static VCardStatus vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) { /* TODO: if we want to support a virtual file system card, we do it here. * It would probably be a pkcs #15 card type */ *response = vcard_make_response( VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); return VCARD_DONE; } /* * VM card (including java cards) */ static VCardStatus vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) { int bytes_to_copy, next_byte_count, count; VCardApplet *current_applet; VCardBufferResponse *buffer_response; vcard_7816_status_t status; /* parse the class first */ if (apdu->a_gen_type != VCARD_7816_ISO) { *response = vcard_make_response( VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); return VCARD_DONE; } /* use a switch so that if we need to support secure channel stuff later, * we know where to put it */ switch (apdu->a_secure_messaging) { case 0x0: /* no SM */ break; case 0x4: /* proprietary SM */ case 0x8: /* header not authenticated */ case 0xc: /* header authenticated */ default: /* for now, don't try to support secure channel stuff in the * virtual card. */ *response = vcard_make_response( VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); return VCARD_DONE; } /* now parse the instruction */ switch (apdu->a_ins) { case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */ case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */ case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */ case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */ case VCARD7816_INS_ERASE_BINARY: /* applet control op */ case VCARD7816_INS_READ_BINARY: /* applet control op */ case VCARD7816_INS_WRITE_BINARY: /* applet control op */ case VCARD7816_INS_UPDATE_BINARY: /* applet control op */ case VCARD7816_INS_READ_RECORD: /* file op */ case VCARD7816_INS_WRITE_RECORD: /* file op */ case VCARD7816_INS_UPDATE_RECORD: /* file op */ case VCARD7816_INS_APPEND_RECORD: /* file op */ case VCARD7816_INS_ENVELOPE: case VCARD7816_INS_PUT_DATA: *response = vcard_make_response( VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); break; case VCARD7816_INS_SELECT_FILE: if (apdu->a_p1 != 0x04) { *response = vcard_make_response( VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); break; } /* side effect, deselect the current applet if no applet has been found * */ current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); vcard_select_applet(card, apdu->a_channel, current_applet); if (current_applet) { unsigned char *aid; int aid_len; aid = vcard_applet_get_aid(current_applet, &aid_len); *response = vcard_response_new(card, aid, aid_len, apdu->a_Le, VCARD7816_STATUS_SUCCESS); } else { *response = vcard_make_response( VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); } break; case VCARD7816_INS_VERIFY: if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { *response = vcard_make_response( VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); } else { if (apdu->a_Lc == 0) { /* handle pin count if possible */ count = vcard_emul_get_login_count(card); if (count < 0) { *response = vcard_make_response( VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); } else { if (count > 0xf) { count = 0xf; } *response = vcard_response_new_status_bytes( VCARD7816_SW1_WARNING_CHANGE, 0xc0 | count); if (*response == NULL) { *response = vcard_make_response( VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); } } } else { status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc); *response = vcard_make_response(status); } } break; case VCARD7816_INS_GET_RESPONSE: buffer_response = vcard_get_buffer_response(card); if (!buffer_response) { *response = vcard_make_response( VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); /* handle error */ break; } bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); *response = vcard_response_new_bytes( card, buffer_response->current, bytes_to_copy, apdu->a_Le, next_byte_count ? VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS, next_byte_count); buffer_response->current += bytes_to_copy; buffer_response->len -= bytes_to_copy; if (*response == NULL || (next_byte_count == 0)) { vcard_set_buffer_response(card, NULL); vcard_buffer_response_delete(buffer_response); } if (*response == NULL) { *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); } break; case VCARD7816_INS_GET_DATA: *response = vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); break; default: *response = vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); break; } /* response should have been set somewhere */ assert(*response != NULL); return VCARD_DONE; } /* * APDU processing starts here. This routes the card processing stuff to the * right location. */ VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) { VCardStatus status; VCardBufferResponse *buffer_response; /* first handle any PTS commands, which aren't really APDU's */ if (apdu->a_type == VCARD_7816_PTS) { /* the PTS responses aren't really responses either */ *response = vcard_response_new_data(apdu->a_data, apdu->a_len); /* PTS responses have no status bytes */ (*response)->b_total_len = (*response)->b_len; return VCARD_DONE; } buffer_response = vcard_get_buffer_response(card); if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { /* clear out buffer_response, return an error */ vcard_set_buffer_response(card, NULL); vcard_buffer_response_delete(buffer_response); *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); return VCARD_DONE; } status = vcard_process_applet_apdu(card, apdu, response); if (status != VCARD_NEXT) { return status; } switch (vcard_get_type(card)) { case VCARD_FILE_SYSTEM: return vcard7816_file_system_process_apdu(card, apdu, response); case VCARD_VM: return vcard7816_vm_process_apdu(card, apdu, response); case VCARD_DIRECT: /* if we are type direct, then the applet should handle everything */ assert(!"VCARD_DIRECT: applet failure"); break; } *response = vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); return VCARD_DONE; }