|  | /* | 
|  | * implement the Java card standard. | 
|  | * | 
|  | * This work is licensed under the terms of 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_7816t.h" | 
|  |  | 
|  | struct VCardAppletStruct { | 
|  | VCardApplet   *next; | 
|  | VCardProcessAPDU process_apdu; | 
|  | VCardResetApplet reset_applet; | 
|  | unsigned char *aid; | 
|  | int aid_len; | 
|  | void *applet_private; | 
|  | VCardAppletPrivateFree applet_private_free; | 
|  | }; | 
|  |  | 
|  | struct VCardStruct { | 
|  | int reference_count; | 
|  | VCardApplet *applet_list; | 
|  | VCardApplet *current_applet[MAX_CHANNEL]; | 
|  | VCardBufferResponse *vcard_buffer_response; | 
|  | VCardType type; | 
|  | VCardEmul *vcard_private; | 
|  | VCardEmulFree vcard_private_free; | 
|  | VCardGetAtr vcard_get_atr; | 
|  | }; | 
|  |  | 
|  | VCardBufferResponse * | 
|  | vcard_buffer_response_new(unsigned char *buffer, int size) | 
|  | { | 
|  | VCardBufferResponse *new_buffer; | 
|  |  | 
|  | new_buffer = (VCardBufferResponse *)g_malloc(sizeof(VCardBufferResponse)); | 
|  | new_buffer->buffer = (unsigned char *)g_malloc(size); | 
|  | memcpy(new_buffer->buffer, buffer, size); | 
|  | new_buffer->buffer_len = size; | 
|  | new_buffer->current = new_buffer->buffer; | 
|  | new_buffer->len = size; | 
|  | return new_buffer; | 
|  | } | 
|  |  | 
|  | void | 
|  | vcard_buffer_response_delete(VCardBufferResponse *buffer_response) | 
|  | { | 
|  | if (buffer_response == NULL) { | 
|  | return; | 
|  | } | 
|  | if (buffer_response->buffer) { | 
|  | g_free(buffer_response->buffer); | 
|  | } | 
|  | g_free(buffer_response); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * clean up state after a reset | 
|  | */ | 
|  | void | 
|  | vcard_reset(VCard *card, VCardPower power) | 
|  | { | 
|  | int i; | 
|  | VCardApplet *applet = NULL; | 
|  |  | 
|  | if (card->type ==  VCARD_DIRECT) { | 
|  | /* select the last applet */ | 
|  | VCardApplet *current_applet = NULL; | 
|  | for (current_applet = card->applet_list; current_applet; | 
|  | current_applet = current_applet->next) { | 
|  | applet = current_applet; | 
|  | } | 
|  | } | 
|  | for (i = 0; i < MAX_CHANNEL; i++) { | 
|  | card->current_applet[i] = applet; | 
|  | } | 
|  | if (card->vcard_buffer_response) { | 
|  | vcard_buffer_response_delete(card->vcard_buffer_response); | 
|  | card->vcard_buffer_response = NULL; | 
|  | } | 
|  | vcard_emul_reset(card, power); | 
|  | if (applet) { | 
|  | applet->reset_applet(card, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* applet utilities */ | 
|  |  | 
|  | /* | 
|  | * applet utilities | 
|  | */ | 
|  | /* constructor */ | 
|  | VCardApplet * | 
|  | vcard_new_applet(VCardProcessAPDU applet_process_function, | 
|  | VCardResetApplet applet_reset_function, | 
|  | unsigned char *aid, int aid_len) | 
|  | { | 
|  | VCardApplet *applet; | 
|  |  | 
|  | applet = (VCardApplet *)g_malloc(sizeof(VCardApplet)); | 
|  | applet->next = NULL; | 
|  | applet->applet_private = NULL; | 
|  | applet->applet_private_free = NULL; | 
|  | applet->process_apdu = applet_process_function; | 
|  | applet->reset_applet = applet_reset_function; | 
|  |  | 
|  | applet->aid = g_malloc(aid_len); | 
|  | memcpy(applet->aid, aid, aid_len); | 
|  | applet->aid_len = aid_len; | 
|  | return applet; | 
|  | } | 
|  |  | 
|  | /* destructor */ | 
|  | void | 
|  | vcard_delete_applet(VCardApplet *applet) | 
|  | { | 
|  | if (applet == NULL) { | 
|  | return; | 
|  | } | 
|  | if (applet->applet_private_free) { | 
|  | applet->applet_private_free(applet->applet_private); | 
|  | applet->applet_private = NULL; | 
|  | } | 
|  | if (applet->aid) { | 
|  | g_free(applet->aid); | 
|  | applet->aid = NULL; | 
|  | } | 
|  | g_free(applet); | 
|  | } | 
|  |  | 
|  | /* accessor */ | 
|  | void | 
|  | vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private, | 
|  | VCardAppletPrivateFree private_free) | 
|  | { | 
|  | if (applet->applet_private_free) { | 
|  | applet->applet_private_free(applet->applet_private); | 
|  | } | 
|  | applet->applet_private = private; | 
|  | applet->applet_private_free = private_free; | 
|  | } | 
|  |  | 
|  | VCard * | 
|  | vcard_new(VCardEmul *private, VCardEmulFree private_free) | 
|  | { | 
|  | VCard *new_card; | 
|  | int i; | 
|  |  | 
|  | new_card = (VCard *)g_malloc(sizeof(VCard)); | 
|  | new_card->applet_list = NULL; | 
|  | for (i = 0; i < MAX_CHANNEL; i++) { | 
|  | new_card->current_applet[i] = NULL; | 
|  | } | 
|  | new_card->vcard_buffer_response = NULL; | 
|  | new_card->type = VCARD_VM; | 
|  | new_card->vcard_private = private; | 
|  | new_card->vcard_private_free = private_free; | 
|  | new_card->vcard_get_atr = NULL; | 
|  | new_card->reference_count = 1; | 
|  | return new_card; | 
|  | } | 
|  |  | 
|  | VCard * | 
|  | vcard_reference(VCard *vcard) | 
|  | { | 
|  | if (vcard == NULL) { | 
|  | return NULL; | 
|  | } | 
|  | vcard->reference_count++; | 
|  | return vcard; | 
|  | } | 
|  |  | 
|  | void | 
|  | vcard_free(VCard *vcard) | 
|  | { | 
|  | VCardApplet *current_applet = NULL; | 
|  | VCardApplet *next_applet = NULL; | 
|  |  | 
|  | if (vcard == NULL) { | 
|  | return; | 
|  | } | 
|  | vcard->reference_count--; | 
|  | if (vcard->reference_count != 0) { | 
|  | return; | 
|  | } | 
|  | if (vcard->vcard_private_free) { | 
|  | (*vcard->vcard_private_free)(vcard->vcard_private); | 
|  | vcard->vcard_private_free = 0; | 
|  | vcard->vcard_private = 0; | 
|  | } | 
|  | for (current_applet = vcard->applet_list; current_applet; | 
|  | current_applet = next_applet) { | 
|  | next_applet = current_applet->next; | 
|  | vcard_delete_applet(current_applet); | 
|  | } | 
|  | vcard_buffer_response_delete(vcard->vcard_buffer_response); | 
|  | g_free(vcard); | 
|  | return; | 
|  | } | 
|  |  | 
|  | void | 
|  | vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len) | 
|  | { | 
|  | if (vcard->vcard_get_atr) { | 
|  | (*vcard->vcard_get_atr)(vcard, atr, atr_len); | 
|  | return; | 
|  | } | 
|  | vcard_emul_get_atr(vcard, atr, atr_len); | 
|  | } | 
|  |  | 
|  | void | 
|  | vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr) | 
|  | { | 
|  | card->vcard_get_atr = vcard_get_atr; | 
|  | } | 
|  |  | 
|  |  | 
|  | VCardStatus | 
|  | vcard_add_applet(VCard *card, VCardApplet *applet) | 
|  | { | 
|  | applet->next = card->applet_list; | 
|  | card->applet_list = applet; | 
|  | /* if our card-type is direct, always call the applet */ | 
|  | if (card->type ==  VCARD_DIRECT) { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < MAX_CHANNEL; i++) { | 
|  | card->current_applet[i] = applet; | 
|  | } | 
|  | } | 
|  | return VCARD_DONE; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * manage applets | 
|  | */ | 
|  | VCardApplet * | 
|  | vcard_find_applet(VCard *card, unsigned char *aid, int aid_len) | 
|  | { | 
|  | VCardApplet *current_applet; | 
|  |  | 
|  | for (current_applet = card->applet_list; current_applet; | 
|  | current_applet = current_applet->next) { | 
|  | if (current_applet->aid_len != aid_len) { | 
|  | continue; | 
|  | } | 
|  | if (memcmp(current_applet->aid, aid, aid_len) == 0) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | return current_applet; | 
|  | } | 
|  |  | 
|  | unsigned char * | 
|  | vcard_applet_get_aid(VCardApplet *applet, int *aid_len) | 
|  | { | 
|  | if (applet == NULL) { | 
|  | return NULL; | 
|  | } | 
|  | *aid_len = applet->aid_len; | 
|  | return applet->aid; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | vcard_select_applet(VCard *card, int channel, VCardApplet *applet) | 
|  | { | 
|  | assert(channel < MAX_CHANNEL); | 
|  | card->current_applet[channel] = applet; | 
|  | /* reset the applet */ | 
|  | if (applet && applet->reset_applet) { | 
|  | applet->reset_applet(card, channel); | 
|  | } | 
|  | } | 
|  |  | 
|  | VCardAppletPrivate * | 
|  | vcard_get_current_applet_private(VCard *card, int channel) | 
|  | { | 
|  | VCardApplet *applet = card->current_applet[channel]; | 
|  |  | 
|  | if (applet == NULL) { | 
|  | return NULL; | 
|  | } | 
|  | return applet->applet_private; | 
|  | } | 
|  |  | 
|  | VCardStatus | 
|  | vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, | 
|  | VCardResponse **response) | 
|  | { | 
|  | if (card->current_applet[apdu->a_channel]) { | 
|  | return card->current_applet[apdu->a_channel]->process_apdu( | 
|  | card, apdu, response); | 
|  | } | 
|  | return VCARD_NEXT; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Accessor functions | 
|  | */ | 
|  | /* accessor functions for the response buffer */ | 
|  | VCardBufferResponse * | 
|  | vcard_get_buffer_response(VCard *card) | 
|  | { | 
|  | return card->vcard_buffer_response; | 
|  | } | 
|  |  | 
|  | void | 
|  | vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer) | 
|  | { | 
|  | card->vcard_buffer_response = buffer; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* accessor functions for the type */ | 
|  | VCardType | 
|  | vcard_get_type(VCard *card) | 
|  | { | 
|  | return card->type; | 
|  | } | 
|  |  | 
|  | void | 
|  | vcard_set_type(VCard *card, VCardType type) | 
|  | { | 
|  | card->type = type; | 
|  | } | 
|  |  | 
|  | /* accessor for private data */ | 
|  | VCardEmul * | 
|  | vcard_get_private(VCard *vcard) | 
|  | { | 
|  | return vcard->vcard_private; | 
|  | } | 
|  |  |