Commit 3b7042ff authored by Robert Relyea's avatar Robert Relyea Committed by Anthony Liguori

libcacard: initial commit

libcacard emulates a Common Access Card (CAC) which is a standard
for smartcards. It is used by the emulated ccid card introduced in
a following patch. Docs are available in docs/libcacard.txt
Signed-off-by: default avatarAlon Levy <alevy@redhat.com>

---

changes from v24->v25:
 * Fix out of tree builds.
 * Fix build with linux-user targets.

changes from v23->v24: (Jes Sorensen review 2)
 * Makefile.target: use obj-$(CONFIG_*) +=
 * remove unrequired includes, include qemu-common before qemu-thread
  * required adding #define NO_NSPR_10_SUPPORT (harmless)

changes from v22->v23:
 * configure fixes: (reported by Stefan Hajnoczi)
  * test a = b, not a == b (second isn't portable)
  * quote $source_path in case it contains spaces
   - this doesn't really help since there are many other places
     that need similar fixes, not introduced by this patch.

changes from v21->v22:
 * fix configure to not link libcacard if nss not found
    (reported by Stefan Hajnoczi)
 * fix vscclient linkage with simpletrace backend
    (reported by Stefan Hajnoczi)
 * card_7816.c: add missing break in ERROR_DATA_NOT_FOUND
    (reported by William van de Velde)

changes from v20->v21: (Jes Sorensen review)
 * use qemu infrastructure: qemu-thread, qemu-common (qemu_malloc
  and qemu_free), error_report
 * assert instead of ASSERT
 * cosmetic fixes
 * use strpbrk and isspace
 * add --disable-nss --enable-nss here, instead of in the final patch.
 * split vscclient, passthru and docs to following patches.

changes from v19->v20:
 * checkpatch.pl

changes from v15->v16:

Build:
 * don't erase self with distclean
 * fix make clean after make distclean
 * Makefile: make vscclient link quiet

Behavioral:
 * vcard_emul_nss: load coolkey in more situations
 * vscclient:
  * use hton,ntoh
  * send init on connect, only start vevent thread on response
  * read payload after header check, before type switch
  * remove Reconnect
  * update for vscard_common changes, empty Flush implementation

Style/Whitespace:
 * fix wrong variable usage
 * remove unused variable
 * use only C style comments
  * add copyright header
  * fix tabulation
Signed-off-by: default avatarAlon Levy <alevy@redhat.com>

libcacard: fix out of tree builds
parent 4ff86189
-include ../config-host.mak
-include $(SRC_PATH)/Makefile.objs
-include $(SRC_PATH)/rules.mak
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard)
ifeq ($(CONFIG_WIN32),y)
QEMU_THREAD=qemu-thread-win32.o
else
QEMU_THREAD=qemu-thread-posix.o
endif
QEMU_OBJS=$(addprefix ../, $(QEMU_THREAD) $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o)
QEMU_CFLAGS+=-I../
clean:
rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~
This diff is collapsed.
/*
* defines the entry point for the cac card. Only used by cac.c anc
* vcard_emul_type.c
*
* 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.
*/
#ifndef CAC_H
#define CAC_H 1
#include "vcard.h"
#include "vreader.h"
/*
* Initialize the cac card. This is the only public function in this file. All
* the rest are connected through function pointers.
*/
VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params,
unsigned char * const *cert, int cert_len[],
VCardKey *key[] /* adopt the keys*/,
int cert_count);
/* not yet implemented */
VCardStatus cac_is_cac_card(VReader *reader);
#endif
This diff is collapsed.
/*
* Implement the 7816 portion of the card spec
*
* 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.
*/
#ifndef CARD_7816_H
#define CARD_7816_H 1
#include "card_7816t.h"
#include "vcardt.h"
/*
* constructors for VCardResponse's
*/
/* response from a return buffer and a status */
VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len,
int Le, vcard_7816_status_t status);
/* response from a return buffer and status bytes */
VCardResponse *vcard_response_new_bytes(VCard *card, unsigned char *buf,
int len, int Le,
unsigned char sw1, unsigned char sw2);
/* response from just status bytes */
VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
unsigned char sw2);
/* response from just status: NOTE this cannot fail, it will alwyas return a
* valid response, if it can't allocate memory, the response will be
* VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */
VCardResponse *vcard_make_response(vcard_7816_status_t status);
/* create a raw response (status has already been encoded */
VCardResponse *vcard_response_new_data(unsigned char *buf, int len);
/*
* destructor for VCardResponse.
* Can be called with a NULL response
*/
void vcard_response_delete(VCardResponse *response);
/*
* constructor for VCardAPDU
*/
VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len,
unsigned short *status);
/*
* destructor for VCardAPDU
* Can be called with a NULL apdu
*/
void vcard_apdu_delete(VCardAPDU *apdu);
/*
* APDU processing starts here. This routes the card processing stuff to the
* right location. Always returns a valid response.
*/
VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu,
VCardResponse **response);
#endif
/*
* Implement the 7816 portion of the card spec
*
* 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.
*/
#ifndef CARD_7816T_H
#define CARD_7816T_H 1
typedef unsigned short vcard_7816_status_t;
struct VCardResponseStruct {
unsigned char *b_data;
vcard_7816_status_t b_status;
unsigned char b_sw1;
unsigned char b_sw2;
int b_len;
int b_total_len;
enum VCardResponseBufferType {
VCARD_MALLOC,
VCARD_MALLOC_DATA,
VCARD_MALLOC_STRUCT,
VCARD_STATIC
} b_type;
};
#define VCARD_RESPONSE_NEW_STATIC_STATUS(stat) \
static const VCardResponse VCardResponse##stat = \
{(unsigned char *)&VCardResponse##stat.b_sw1, (stat), ((stat) >> 8), \
((stat) & 0xff), 0, 2, VCARD_STATIC};
#define VCARD_RESPONSE_NEW_STATIC_STATUS_BYTES(sw1, sw2) \
static const VCardResponse VCARDResponse##sw1 = \
{(unsigned char *)&VCardResponse##name.b_sw1, ((sw1) << 8 | (sw2)), \
(sw1), (sw2), 0, 2, VCARD_STATIC};
/* cast away the const, callers need may need to 'free' the
* result, and const implies that they don't */
#define VCARD_RESPONSE_GET_STATIC(name) \
((VCardResponse *)(&VCardResponse##name))
typedef enum {
VCARD_7816_ISO,
VCARD_7816_RFU,
VCARD_7816_PTS,
VCARD_7816_PROPIETARY
} VCardAPDUType;
/*
* 7816 header. All APDU's have this header.
* They must be laid out in this order.
*/
struct VCardAPDUHeader {
unsigned char ah_cla;
unsigned char ah_ins;
unsigned char ah_p1;
unsigned char ah_p2;
unsigned char ah_Le;
unsigned char ah_body[1]; /* indefinate length */
};
/*
* 7816 APDU structure. The raw bytes are stored in the union and can be
* accessed directly through u.data (which is aliased as a_data).
*
* Names of the fields match the 7816 documentation.
*/
struct VCardAPDUStruct {
int a_len; /* length of the whole buffer, including header */
int a_Lc; /* 7816 Lc (parameter length) value */
int a_Le; /* 7816 Le (expected result length) value */
unsigned char *a_body; /* pointer to the parameter */
int a_channel; /* decoded channel */
int a_secure_messaging; /* decoded secure messaging type */
int a_type; /* decoded type from cla (top nibble of class) */
VCardAPDUType a_gen_type; /* generic type (7816, PROPRIETARY, RFU, etc) */
union {
struct VCardAPDUHeader *header;
unsigned char *data;
} u;
/* give the subfields a unified look */
#define a_header u.header
#define a_data u.data
#define a_cla a_header->ah_cla /* class */
#define a_ins a_header->ah_ins /* instruction */
#define a_p1 a_header->ah_p1 /* parameter 1 */
#define a_p2 a_header->ah_p2 /* parameter 2 */
};
/* 7816 status codes */
#define VCARD7816_STATUS_SUCCESS 0x9000
#define VCARD7816_STATUS_WARNING 0x6200
#define VCARD7816_STATUS_WARNING_RET_CORUPT 0x6281
#define VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE 0x6282
#define VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED 0x6283
#define VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID 0x6284
#define VCARD7816_STATUS_WARNING_CHANGE 0x6300
#define VCARD7816_STATUS_WARNING_FILE_FILLED 0x6381
#define VCARD7816_STATUS_EXC_ERROR 0x6400
#define VCARD7816_STATUS_EXC_ERROR_CHANGE 0x6500
#define VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE 0x6581
#define VCARD7816_STATUS_ERROR_WRONG_LENGTH 0x6700
#define VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED 0x6800
#define VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED 0x6881
#define VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED 0x6882
#define VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED 0x6900
#define VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE 0x6981
#define VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED 0x6982
#define VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED 0x6983
#define VCARD7816_STATUS_ERROR_DATA_INVALID 0x6984
#define VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED 0x6985
#define VCARD7816_STATUS_ERROR_DATA_NO_EF 0x6986
#define VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING 0x6987
#define VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT 0x6988
#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS 0x6a00
#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA 0x6a80
#define VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED 0x6a81
#define VCARD7816_STATUS_ERROR_FILE_NOT_FOUND 0x6a82
#define VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND 0x6a83
#define VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE 0x6a84
#define VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT 0x6a85
#define VCARD7816_STATUS_ERROR_P1_P2_INCORRECT 0x6a86
#define VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT 0x6a87
#define VCARD7816_STATUS_ERROR_DATA_NOT_FOUND 0x6a88
#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2 0x6b00
#define VCARD7816_STATUS_ERROR_INS_CODE_INVALID 0x6d00
#define VCARD7816_STATUS_ERROR_CLA_INVALID 0x6e00
#define VCARD7816_STATUS_ERROR_GENERAL 0x6f00
/* 7816 sw1 codes */
#define VCARD7816_SW1_SUCCESS 0x90
#define VCARD7816_SW1_RESPONSE_BYTES 0x61
#define VCARD7816_SW1_WARNING 0x62
#define VCARD7816_SW1_WARNING_CHANGE 0x63
#define VCARD7816_SW1_EXC_ERROR 0x64
#define VCARD7816_SW1_EXC_ERROR_CHANGE 0x65
#define VCARD7816_SW1_ERROR_WRONG_LENGTH 0x67
#define VCARD7816_SW1_CLA_ERROR 0x68
#define VCARD7816_SW1_COMMAND_ERROR 0x69
#define VCARD7816_SW1_P1_P2_ERROR 0x6a
#define VCARD7816_SW1_LE_ERROR 0x6c
#define VCARD7816_SW1_INS_ERROR 0x6d
#define VCARD7816_SW1_CLA_NOT_SUPPORTED 0x6e
/* 7816 Instructions */
#define VCARD7816_INS_MANAGE_CHANNEL 0x70
#define VCARD7816_INS_EXTERNAL_AUTHENTICATE 0x82
#define VCARD7816_INS_GET_CHALLENGE 0x84
#define VCARD7816_INS_INTERNAL_AUTHENTICATE 0x88
#define VCARD7816_INS_ERASE_BINARY 0x0e
#define VCARD7816_INS_READ_BINARY 0xb0
#define VCARD7816_INS_WRITE_BINARY 0xd0
#define VCARD7816_INS_UPDATE_BINARY 0xd6
#define VCARD7816_INS_READ_RECORD 0xb2
#define VCARD7816_INS_WRITE_RECORD 0xd2
#define VCARD7816_INS_UPDATE_RECORD 0xdc
#define VCARD7816_INS_APPEND_RECORD 0xe2
#define VCARD7816_INS_ENVELOPE 0xc2
#define VCARD7816_INS_PUT_DATA 0xda
#define VCARD7816_INS_GET_DATA 0xca
#define VCARD7816_INS_SELECT_FILE 0xa4
#define VCARD7816_INS_VERIFY 0x20
#define VCARD7816_INS_GET_RESPONSE 0xc0
#endif
/*
* event queue implementation.
*
* 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 "qemu-thread.h"
#include "vcard.h"
#include "vreader.h"
#include "vevent.h"
VEvent *
vevent_new(VEventType type, VReader *reader, VCard *card)
{
VEvent *new_vevent;
new_vevent = (VEvent *)qemu_malloc(sizeof(VEvent));
new_vevent->next = NULL;
new_vevent->type = type;
new_vevent->reader = vreader_reference(reader);
new_vevent->card = vcard_reference(card);
return new_vevent;
}
void
vevent_delete(VEvent *vevent)
{
if (vevent == NULL) {
return;
}
vreader_free(vevent->reader);
vcard_free(vevent->card);
qemu_free(vevent);
}
/*
* VEvent queue management
*/
static VEvent *vevent_queue_head;
static VEvent *vevent_queue_tail;
static QemuMutex vevent_queue_lock;
static QemuCond vevent_queue_condition;
void vevent_queue_init(void)
{
qemu_mutex_init(&vevent_queue_lock);
qemu_cond_init(&vevent_queue_condition);
vevent_queue_head = vevent_queue_tail = NULL;
}
void
vevent_queue_vevent(VEvent *vevent)
{
vevent->next = NULL;
qemu_mutex_lock(&vevent_queue_lock);
if (vevent_queue_head) {
assert(vevent_queue_tail);
vevent_queue_tail->next = vevent;
} else {
vevent_queue_head = vevent;
}
vevent_queue_tail = vevent;
qemu_cond_signal(&vevent_queue_condition);
qemu_mutex_unlock(&vevent_queue_lock);
}
/* must have lock */
static VEvent *
vevent_dequeue_vevent(void)
{
VEvent *vevent = NULL;
if (vevent_queue_head) {
vevent = vevent_queue_head;
vevent_queue_head = vevent->next;
vevent->next = NULL;
}
return vevent;
}
VEvent *vevent_wait_next_vevent(void)
{
VEvent *vevent;
qemu_mutex_lock(&vevent_queue_lock);
while ((vevent = vevent_dequeue_vevent()) == NULL) {
qemu_cond_wait(&vevent_queue_condition, &vevent_queue_lock);
}
qemu_mutex_unlock(&vevent_queue_lock);
return vevent;
}
VEvent *vevent_get_next_vevent(void)
{
VEvent *vevent;
qemu_mutex_lock(&vevent_queue_lock);
vevent = vevent_dequeue_vevent();
qemu_mutex_unlock(&vevent_queue_lock);
return vevent;
}
/*
* 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.
*/
#ifndef EVENTT_H
#define EVENTT_H 1
#include "vreadert.h"
#include "vcardt.h"
typedef struct VEventStruct VEvent;
typedef enum {
VEVENT_READER_INSERT,
VEVENT_READER_REMOVE,
VEVENT_CARD_INSERT,
VEVENT_CARD_REMOVE,
VEVENT_LAST,
} VEventType;
struct VEventStruct {
VEvent *next;
VEventType type;
VReader *reader;
VCard *card;
};
#endif
/*
* 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 <stdio.h>
#include "vcard.h"
VCardStatus cac_card_init(const char *flags, VCard *card,
const unsigned char *cert[],
int cert_len[], VCardKey *key[] /* adopt the keys*/,
int cert_count);
/*
* this will crash... just test the linkage right now
*/
main(int argc, char **argv)
{
VCard *card; /* no constructor yet */
cac_card_init("", card, NULL, 0, NULL, 0);
}
/*
* 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 *)qemu_malloc(sizeof(VCardBufferResponse));
new_buffer->buffer = (unsigned char *)qemu_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) {
qemu_free(buffer_response->buffer);
}
qemu_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 *)qemu_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 = qemu_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) {
qemu_free(applet->aid);
applet->aid = NULL;
}
qemu_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 *)qemu_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);
qemu_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