Merge pull request #694 from germanblanco/dnie_memory_leaks_and_sm_wrapping
DNIe. Removing all memory leaks and using SM wrapping and unwrapping.
This commit is contained in:
commit
192c3f6182
@ -53,6 +53,9 @@
|
||||
#ifdef __APPLE__
|
||||
#include <Carbon/Carbon.h>
|
||||
#endif
|
||||
|
||||
#define MAX_RESP_BUFFER_SIZE 2048
|
||||
|
||||
/* default titles */
|
||||
#define USER_CONSENT_TITLE "Confirm"
|
||||
|
||||
@ -619,7 +622,7 @@ static int dnie_get_serialnr(sc_card_t * card, sc_serial_number_t * serial)
|
||||
{
|
||||
int result;
|
||||
sc_apdu_t apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 rbuf[MAX_RESP_BUFFER_SIZE];
|
||||
if ((card == NULL) || (card->ctx == NULL) || (serial == NULL))
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
@ -729,6 +732,73 @@ int dnie_match_card(struct sc_card *card)
|
||||
LOG_FUNC_RETURN(card->ctx, result);
|
||||
}
|
||||
|
||||
static int dnie_sm_free_wrapped_apdu(struct sc_card *card,
|
||||
struct sc_apdu *plain, struct sc_apdu **sm_apdu)
|
||||
{
|
||||
struct sc_context *ctx = card->ctx;
|
||||
int rv = SC_SUCCESS;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
if (!sm_apdu)
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
if (!(*sm_apdu))
|
||||
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
||||
|
||||
if ((*sm_apdu) != plain) {
|
||||
plain->resp = (*sm_apdu)->resp;
|
||||
plain->resplen = (*sm_apdu)->resplen;
|
||||
plain->sw1 = (*sm_apdu)->sw1;
|
||||
plain->sw2 = (*sm_apdu)->sw2;
|
||||
|
||||
if (((*sm_apdu)->data) != plain->data)
|
||||
free((unsigned char *) (*sm_apdu)->data);
|
||||
free(*sm_apdu);
|
||||
}
|
||||
*sm_apdu = NULL;
|
||||
|
||||
LOG_FUNC_RETURN(ctx, rv);
|
||||
}
|
||||
|
||||
static int dnie_sm_get_wrapped_apdu(struct sc_card *card,
|
||||
struct sc_apdu *plain, struct sc_apdu **sm_apdu)
|
||||
{
|
||||
struct sc_context *ctx = card->ctx;
|
||||
struct sc_apdu *apdu = NULL;
|
||||
cwa_provider_t *provider = NULL;
|
||||
int rv = SC_SUCCESS;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
if (!plain || !sm_apdu)
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
|
||||
|
||||
if (((plain->cla & 0x0C) == 0) && (plain->ins != 0xC0)) {
|
||||
*sm_apdu = NULL;
|
||||
//construct new SM apdu from original apdu
|
||||
apdu = calloc(1, sizeof(struct sc_apdu));
|
||||
if (!apdu)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(apdu, plain, sizeof(sc_apdu_t));
|
||||
|
||||
rv = cwa_encode_apdu(card, provider, plain, apdu);
|
||||
|
||||
if (rv != SC_SUCCESS) {
|
||||
dnie_sm_free_wrapped_apdu(card, NULL, &apdu);
|
||||
goto err;
|
||||
}
|
||||
|
||||
*sm_apdu = apdu;
|
||||
} else
|
||||
*sm_apdu = plain;
|
||||
|
||||
apdu = NULL;
|
||||
err:
|
||||
free(apdu);
|
||||
LOG_FUNC_RETURN(ctx, rv);
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenDNIe card structures initialization.
|
||||
*
|
||||
@ -759,8 +829,9 @@ static int dnie_init(struct sc_card *card)
|
||||
#ifdef ENABLE_SM
|
||||
/** Secure messaging initialization section **/
|
||||
memset(&(card->sm_ctx), 0, sizeof(sm_context_t));
|
||||
card->sm_ctx.ops.get_sm_apdu = NULL;
|
||||
card->sm_ctx.ops.free_sm_apdu = NULL;
|
||||
card->sm_ctx.ops.get_sm_apdu = dnie_sm_get_wrapped_apdu;
|
||||
card->sm_ctx.ops.free_sm_apdu = dnie_sm_free_wrapped_apdu;
|
||||
card->sm_ctx.sm_mode = SM_MODE_NONE;
|
||||
#endif
|
||||
|
||||
init_flags(card);
|
||||
@ -916,7 +987,7 @@ static u8 *dnie_uncompress(sc_card_t * card, u8 * from, size_t *len)
|
||||
*/
|
||||
static int dnie_fill_cache(sc_card_t * card)
|
||||
{
|
||||
u8 tmp[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 tmp[MAX_RESP_BUFFER_SIZE];
|
||||
sc_apdu_t apdu;
|
||||
size_t count = 0;
|
||||
size_t len = 0;
|
||||
@ -944,7 +1015,7 @@ static int dnie_fill_cache(sc_card_t * card)
|
||||
apdu.p1 = 0xff & (len >> 8);
|
||||
apdu.p2 = 0xff & len;
|
||||
apdu.le = count;
|
||||
apdu.resplen = count;
|
||||
apdu.resplen = MAX_RESP_BUFFER_SIZE;
|
||||
apdu.resp = tmp;
|
||||
/* transmit apdu */
|
||||
r = dnie_transmit_apdu(card, &apdu);
|
||||
@ -1070,7 +1141,7 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa
|
||||
{
|
||||
int res = 0;
|
||||
sc_apdu_t apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 rbuf[MAX_RESP_BUFFER_SIZE];
|
||||
sc_file_t *file = NULL;
|
||||
|
||||
sc_context_t *ctx = NULL;
|
||||
@ -1081,17 +1152,15 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
|
||||
/* Arriving here means need to compose and send apdu */
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, p1, 0,
|
||||
sc_get_max_recv_size(card), pathlen,
|
||||
rbuf, sizeof(rbuf), path, pathlen);
|
||||
if (p1 == 3)
|
||||
apdu.cse= SC_APDU_CASE_1;
|
||||
|
||||
if (file_out == NULL) {
|
||||
apdu.cse = (apdu.lc == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT;
|
||||
apdu.le = 0;
|
||||
}
|
||||
if (file_out == NULL)
|
||||
apdu.cse = SC_APDU_CASE_4_SHORT;
|
||||
|
||||
res = dnie_transmit_apdu(card, &apdu);
|
||||
if ((res != SC_SUCCESS) || (file_out == NULL))
|
||||
dnie_free_apdu_buffers(&apdu, rbuf, sizeof(rbuf));
|
||||
@ -1196,7 +1265,6 @@ static int dnie_select_file(struct sc_card *card,
|
||||
|
||||
sc_log(ctx, "select_file(PATH): requested:%s ", sc_dump_hex(in_path->value, in_path->len));
|
||||
|
||||
|
||||
/* convert to SC_PATH_TYPE_FILE_ID */
|
||||
res = sc_lock(card); /* lock to ensure path traversal */
|
||||
LOG_TEST_RET(ctx, res, "sc_lock() failed");
|
||||
@ -1269,10 +1337,12 @@ static int dnie_select_file(struct sc_card *card,
|
||||
* @param len requested challenge length
|
||||
* @return SC_SUCCESS if OK; else error code
|
||||
*/
|
||||
#define BUFFER_SIZE 8
|
||||
|
||||
static int dnie_get_challenge(struct sc_card *card, u8 * rnd, size_t len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
u8 buf[10];
|
||||
u8 buf[MAX_RESP_BUFFER_SIZE];
|
||||
int result = SC_SUCCESS;
|
||||
if ((card == NULL) || (card->ctx == NULL))
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
@ -1284,27 +1354,31 @@ static int dnie_get_challenge(struct sc_card *card, u8 * rnd, size_t len)
|
||||
result = SC_ERROR_INVALID_ARGUMENTS;
|
||||
goto dnie_get_challenge_error;
|
||||
}
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00, 8, 0,
|
||||
buf, 8, NULL, 0);
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00, BUFFER_SIZE, 0,
|
||||
buf, MAX_RESP_BUFFER_SIZE, NULL, 0);
|
||||
|
||||
/*
|
||||
* As DNIe cannot handle other data length than 0x08 and 0x14,
|
||||
* perform consecutive reads of 8 bytes until retrieve requested length
|
||||
*/
|
||||
while (len > 0) {
|
||||
size_t n = len > 8 ? 8 : len;
|
||||
size_t n = len > BUFFER_SIZE ? BUFFER_SIZE : len;
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
|
||||
apdu.le = BUFFER_SIZE;
|
||||
apdu.resp = buf;
|
||||
apdu.resplen = MAX_RESP_BUFFER_SIZE; /* include SW's */
|
||||
result = dnie_transmit_apdu(card, &apdu);
|
||||
if (result != SC_SUCCESS) {
|
||||
dnie_free_apdu_buffers(&apdu, buf, 8);
|
||||
dnie_free_apdu_buffers(&apdu, buf, MAX_RESP_BUFFER_SIZE);
|
||||
LOG_TEST_RET(card->ctx, result, "APDU transmit failed");
|
||||
}
|
||||
if (apdu.resplen != 8) {
|
||||
if (apdu.resplen != BUFFER_SIZE) {
|
||||
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
dnie_free_apdu_buffers(&apdu, buf, 8);
|
||||
dnie_free_apdu_buffers(&apdu, buf, MAX_RESP_BUFFER_SIZE);
|
||||
goto dnie_get_challenge_error;
|
||||
}
|
||||
memcpy(rnd, apdu.resp, n);
|
||||
dnie_free_apdu_buffers(&apdu, buf, 8);
|
||||
dnie_free_apdu_buffers(&apdu, buf, MAX_RESP_BUFFER_SIZE);
|
||||
len -= n;
|
||||
rnd += n;
|
||||
}
|
||||
@ -1363,6 +1437,7 @@ static int dnie_set_security_env(struct sc_card *card,
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; /* buffer to compose apdu data */
|
||||
u8 rbuf[MAX_RESP_BUFFER_SIZE];
|
||||
u8 *p = sbuf;
|
||||
int result = SC_SUCCESS;
|
||||
if ((card == NULL) || (card->ctx == NULL) || (env == NULL))
|
||||
@ -1434,8 +1509,8 @@ static int dnie_set_security_env(struct sc_card *card,
|
||||
}
|
||||
|
||||
/* create and format apdu */
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x00, 0x00, 0, p - sbuf,
|
||||
NULL, 0, sbuf, p - sbuf);
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x22, 0x00, 0x00, 255, p - sbuf,
|
||||
rbuf, MAX_RESP_BUFFER_SIZE, sbuf, p - sbuf);
|
||||
|
||||
/* check and perform operation */
|
||||
switch (env->operation) {
|
||||
@ -1463,7 +1538,7 @@ static int dnie_set_security_env(struct sc_card *card,
|
||||
|
||||
/* send composed apdu and parse result */
|
||||
result = dnie_transmit_apdu(card, &apdu);
|
||||
dnie_free_apdu_buffers(&apdu, NULL, 0);
|
||||
dnie_free_apdu_buffers(&apdu, rbuf, MAX_RESP_BUFFER_SIZE);
|
||||
LOG_TEST_RET(card->ctx, result, "Set Security Environment failed");
|
||||
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
|
||||
@ -1497,7 +1572,7 @@ static int dnie_decipher(struct sc_card *card,
|
||||
{
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 sbuf[MAX_RESP_BUFFER_SIZE];
|
||||
size_t len;
|
||||
int result = SC_SUCCESS;
|
||||
if ((card == NULL) || (card->ctx == NULL))
|
||||
@ -1571,7 +1646,7 @@ static int dnie_compute_signature(struct sc_card *card,
|
||||
int result = SC_SUCCESS;
|
||||
int result_resplen = 0;
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; /* to receive sign response */
|
||||
u8 rbuf[MAX_RESP_BUFFER_SIZE]; /* to receive sign response */
|
||||
|
||||
/* some preliminar checks */
|
||||
if ((card == NULL) || (card->ctx == NULL))
|
||||
@ -1666,7 +1741,7 @@ static int dnie_list_files(sc_card_t * card, u8 * buf, size_t buflen)
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
/* compose select_file(ID) command */
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x00, 0, 2,
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00, 0, 2,
|
||||
NULL, 0, data, 2);
|
||||
/* iterate on every possible ids */
|
||||
for (id1 = 0; id1 < 256; id1++) {
|
||||
@ -1824,7 +1899,7 @@ static int dnie_read_header(struct sc_card *card)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
int r;
|
||||
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 buf[MAX_RESP_BUFFER_SIZE];
|
||||
unsigned long uncompressed = 0L;
|
||||
unsigned long compressed = 0L;
|
||||
sc_context_t *ctx = NULL;
|
||||
@ -1836,7 +1911,7 @@ static int dnie_read_header(struct sc_card *card)
|
||||
|
||||
/* initialize apdu */
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, 0x00, 0x00, 8, 0,
|
||||
buf, SC_MAX_APDU_BUFFER_SIZE, NULL, 0);
|
||||
buf, MAX_RESP_BUFFER_SIZE, NULL, 0);
|
||||
/* transmit apdu */
|
||||
r = dnie_transmit_apdu(card, &apdu);
|
||||
if (r != SC_SUCCESS) {
|
||||
@ -2090,6 +2165,7 @@ static int dnie_pin_verify(struct sc_card *card,
|
||||
sc_apdu_t apdu;
|
||||
|
||||
u8 pinbuffer[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 resp[MAX_RESP_BUFFER_SIZE];
|
||||
int pinlen = 0;
|
||||
int padding = 0;
|
||||
|
||||
@ -2109,13 +2185,13 @@ static int dnie_pin_verify(struct sc_card *card,
|
||||
pinlen = res;
|
||||
|
||||
/* compose apdu */
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, 0x00, 0x00, pinlen,
|
||||
NULL, 0, pinbuffer, pinlen);
|
||||
dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x20, 0x00, 0x00, 255, pinlen,
|
||||
resp, MAX_RESP_BUFFER_SIZE, pinbuffer, pinlen);
|
||||
|
||||
/* and send to card throught virtual channel */
|
||||
res = dnie_transmit_apdu(card, &apdu);
|
||||
if (res != SC_SUCCESS) {
|
||||
dnie_free_apdu_buffers(&apdu, NULL, 0);
|
||||
dnie_free_apdu_buffers(&apdu, resp, MAX_RESP_BUFFER_SIZE);
|
||||
LOG_TEST_RET(card->ctx, res, "VERIFY APDU Transmit fail");
|
||||
}
|
||||
|
||||
@ -2123,14 +2199,14 @@ static int dnie_pin_verify(struct sc_card *card,
|
||||
if (tries_left != NULL) { /* returning tries_left count is requested */
|
||||
if ((apdu.sw1 == 0x63) && ((apdu.sw2 & 0xF0) == 0xC0)) {
|
||||
*tries_left = apdu.sw2 & 0x0F;
|
||||
dnie_free_apdu_buffers(&apdu, NULL, 0);
|
||||
dnie_free_apdu_buffers(&apdu, resp, MAX_RESP_BUFFER_SIZE);
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
|
||||
}
|
||||
}
|
||||
res = dnie_check_sw(card, apdu.sw1, apdu.sw2); /* not a pinerr: parse result */
|
||||
|
||||
/* the end: a bit of Mister Proper and return */
|
||||
dnie_free_apdu_buffers(&apdu, NULL, 0);
|
||||
dnie_free_apdu_buffers(&apdu, resp, MAX_RESP_BUFFER_SIZE);
|
||||
data->apdu = NULL;
|
||||
LOG_FUNC_RETURN(card->ctx, res);
|
||||
#else
|
||||
|
@ -619,6 +619,13 @@ static int dnie_create_pre_ops(sc_card_t * card, cwa_provider_t * provider)
|
||||
return sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
|
||||
}
|
||||
|
||||
static int dnie_create_post_ops(sc_card_t * card, cwa_provider_t * provider)
|
||||
{
|
||||
card->sm_ctx.sm_mode = SM_MODE_TRANSMIT;
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point for DNIe CWA14890 SM data provider.
|
||||
*
|
||||
@ -638,7 +645,7 @@ cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card)
|
||||
|
||||
/* pre and post operations */
|
||||
res->cwa_create_pre_ops = dnie_create_pre_ops;
|
||||
res->cwa_create_post_ops = NULL;
|
||||
res->cwa_create_post_ops = dnie_create_post_ops;
|
||||
|
||||
/* Get ICC intermediate CA path */
|
||||
res->cwa_get_icc_intermediate_ca_cert =
|
||||
@ -675,239 +682,26 @@ cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card)
|
||||
/* Get ICC Serial Number */
|
||||
res->cwa_get_sn_icc = dnie_get_sn_icc;
|
||||
|
||||
/************** operations related with APDU encoding ******************/
|
||||
|
||||
/* pre and post operations */
|
||||
res->cwa_encode_pre_ops = NULL;
|
||||
res->cwa_encode_post_ops = NULL;
|
||||
|
||||
/************** operations related APDU response decoding **************/
|
||||
|
||||
/* pre and post operations */
|
||||
res->cwa_decode_pre_ops = NULL;
|
||||
res->cwa_decode_post_ops = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
|
||||
{
|
||||
u8 buf[MAX_RESP_BUFFER_SIZE]; /* use for store partial le responses */
|
||||
int res = SC_SUCCESS;
|
||||
cwa_provider_t *provider = NULL;
|
||||
if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL))
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
/* check if envelope is needed */
|
||||
if (apdu->lc <= card->max_send_size) {
|
||||
int tmp;
|
||||
/* no envelope needed */
|
||||
sc_log(card->ctx, "envelope tx is not required");
|
||||
|
||||
tmp = apdu->cse; /* save original apdu type */
|
||||
/* if SM is on, assure rx buffer exists and force get_response */
|
||||
if (provider->status.session.state == CWA_SM_ACTIVE) {
|
||||
if (tmp == SC_APDU_CASE_3_SHORT)
|
||||
apdu->cse = SC_APDU_CASE_4_SHORT;
|
||||
if (apdu->resplen == 0) { /* no response buffer: create */
|
||||
apdu->resp = calloc(1, MAX_RESP_BUFFER_SIZE);
|
||||
if (apdu->resp == NULL)
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
||||
apdu->resplen = MAX_RESP_BUFFER_SIZE;
|
||||
apdu->le = card->max_recv_size;
|
||||
}
|
||||
}
|
||||
/* call std sc_transmit_apdu */
|
||||
res = sc_transmit_apdu(card, apdu);
|
||||
/* and restore original apdu type */
|
||||
apdu->cse = tmp;
|
||||
} else {
|
||||
|
||||
size_t e_txlen = 0;
|
||||
size_t index = 0;
|
||||
sc_apdu_t e_apdu;
|
||||
u8 * e_tx = NULL;
|
||||
|
||||
/* envelope needed */
|
||||
sc_log(card->ctx, "envelope tx required: lc:%d", apdu->lc);
|
||||
|
||||
e_tx = calloc(7 + apdu->datalen, sizeof(u8)); /* enveloped data */
|
||||
|
||||
if (!e_tx)
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
/* copy apdu info into enveloped data */
|
||||
*(e_tx + 0) = apdu->cla; /* apdu header */
|
||||
*(e_tx + 1) = apdu->ins;
|
||||
*(e_tx + 2) = apdu->p1;
|
||||
*(e_tx + 3) = apdu->p2;
|
||||
*(e_tx + 4) = 0x00; /* length in extended format */
|
||||
*(e_tx + 5) = 0xff & (apdu->lc >> 8);
|
||||
*(e_tx + 6) = 0xff & apdu->lc;
|
||||
memcpy(e_tx + 7, apdu->data, apdu->lc);
|
||||
e_txlen = 7 + apdu->lc;
|
||||
/* sc_log(card->ctx, "Data to be enveloped & sent: (%d bytes)\n%s\n===============================================================",e_txlen,sc_dump_hex(e_tx,e_txlen)); */
|
||||
/* split apdu in n chunks of max_send_size len */
|
||||
for (index = 0; index < e_txlen; index += card->max_send_size) {
|
||||
size_t len = MIN(card->max_send_size, e_txlen - index);
|
||||
sc_log(card->ctx, "envelope tx offset:%04X size:%02X",
|
||||
index, len);
|
||||
|
||||
/* compose envelope apdu command */
|
||||
dnie_format_apdu(card, &e_apdu, apdu->cse, 0xC2, 0x00, 0x00, apdu->le, len,
|
||||
apdu->resp, apdu->resplen, e_tx + index, len);
|
||||
e_apdu.cla = 0x90; /* propietary CLA */
|
||||
/* if SM is ON, ensure resp exists, and force getResponse() */
|
||||
if (provider->status.session.state == CWA_SM_ACTIVE) {
|
||||
/* set up proper apdu type */
|
||||
if (e_apdu.cse == SC_APDU_CASE_3_SHORT)
|
||||
e_apdu.cse = SC_APDU_CASE_4_SHORT;
|
||||
/* if no response buffer: create */
|
||||
if (apdu->resplen == 0) {
|
||||
e_apdu.resp = buf;
|
||||
e_apdu.resplen = 2048;
|
||||
e_apdu.le = card->max_recv_size;
|
||||
}
|
||||
}
|
||||
/* send data chunk bypassing apdu wrapping */
|
||||
res = sc_transmit_apdu(card, &e_apdu);
|
||||
if (res != SC_SUCCESS) {
|
||||
if (e_tx) {
|
||||
free(e_tx);
|
||||
e_tx = NULL;
|
||||
}
|
||||
sc_log(card->ctx, "Error in envelope() send apdu");
|
||||
LOG_FUNC_RETURN(card->ctx, res);
|
||||
}
|
||||
} /* for */
|
||||
if (e_tx) {
|
||||
free(e_tx);
|
||||
e_tx = NULL;
|
||||
}
|
||||
/* last apdu sent contains response to enveloped cmd */
|
||||
apdu->resp = calloc(1, MAX_RESP_BUFFER_SIZE);
|
||||
if (apdu->resp == NULL)
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
||||
memcpy(apdu->resp, e_apdu.resp, e_apdu.resplen);
|
||||
apdu->resplen = e_apdu.resplen;
|
||||
res = SC_SUCCESS;
|
||||
}
|
||||
LOG_FUNC_RETURN(card->ctx, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* APDU Wrapping routine.
|
||||
*
|
||||
* Called before sc_transmit_apdu() to allowing APDU wrapping
|
||||
* If set to NULL no wrapping process will be done
|
||||
* Usefull on Secure Messaging APDU encode/decode
|
||||
* If returned value is greater than zero, do_single_transmit()
|
||||
* will be called, else means either SC_SUCCESS or error code
|
||||
*
|
||||
* NOTE:
|
||||
* DNIe doesn't handle apdu chaining; instead apdus with
|
||||
* lc>max_send_size are sent by mean of envelope() apdu command
|
||||
* So we use this method for
|
||||
* - encode and decode SM if SM is on
|
||||
* - use envelope instead of apdu chain if lc>max_send_size
|
||||
*
|
||||
* @param card Pointer to Card Structure
|
||||
* @param apdu to be wrapped
|
||||
* @return
|
||||
* - positive: use OpenSC's sc_transmit_apdu()
|
||||
* - negative: error
|
||||
* - zero: success: no need to further transmission
|
||||
*/
|
||||
static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
|
||||
{
|
||||
int res = SC_SUCCESS;
|
||||
sc_apdu_t wrapped;
|
||||
sc_context_t *ctx;
|
||||
cwa_provider_t *provider = NULL;
|
||||
int retries = 3;
|
||||
char * msg = NULL;
|
||||
|
||||
if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL))
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
ctx=card->ctx;
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
|
||||
for (retries=3; retries>0; retries--) {
|
||||
/* preserve original apdu to take care of retransmission */
|
||||
memcpy(&wrapped, apdu, sizeof(sc_apdu_t));
|
||||
/* SM is active, encode apdu */
|
||||
if (provider->status.session.state == CWA_SM_ACTIVE) {
|
||||
wrapped.resp = NULL;
|
||||
wrapped.resplen = 0; /* let get_response() assign space */
|
||||
res = cwa_encode_apdu(card, provider, apdu, &wrapped);
|
||||
if (res != SC_SUCCESS) {
|
||||
msg = "Error in cwa_encode_apdu process";
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
}
|
||||
/* send apdu via envelope() cmd if needed */
|
||||
res = dnie_transmit_apdu_internal(card, &wrapped);
|
||||
/* check for tx errors */
|
||||
if (res != SC_SUCCESS) {
|
||||
msg = "Error in dnie_transmit_apdu process";
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
|
||||
/* parse response and handle SM related errors */
|
||||
res=card->ops->check_sw(card,wrapped.sw1,wrapped.sw2);
|
||||
if ( res == SC_ERROR_SM ) {
|
||||
sc_log(ctx,"Detected SM error/collision. Try %d",retries);
|
||||
switch(provider->status.session.state) {
|
||||
/* No SM or creating: collision with other process
|
||||
just retry as SM error reset ICC SM state */
|
||||
case CWA_SM_NONE:
|
||||
case CWA_SM_INPROGRESS:
|
||||
continue;
|
||||
/* SM was active: force restart SM and retry */
|
||||
case CWA_SM_ACTIVE:
|
||||
res=cwa_create_secure_channel(card, provider, CWA_SM_COLD);
|
||||
if (res != SC_SUCCESS) {
|
||||
msg = "Cannot re-enable SM";
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* if SM is active; decode apdu */
|
||||
if (provider->status.session.state == CWA_SM_ACTIVE) {
|
||||
apdu->resp = NULL;
|
||||
apdu->resplen = 0; /* let cwa_decode_response() eval & create size */
|
||||
res = cwa_decode_response(card, provider, &wrapped, apdu);
|
||||
if (res != SC_SUCCESS)
|
||||
msg = "Error in cwa_decode_response process";
|
||||
goto cleanup_and_return;
|
||||
} else {
|
||||
if (apdu->resp != wrapped.resp) free(apdu->resp);
|
||||
/* memcopy result to original apdu */
|
||||
memcpy(apdu, &wrapped, sizeof(sc_apdu_t));
|
||||
LOG_FUNC_RETURN(ctx, res);
|
||||
}
|
||||
}
|
||||
msg = "Too many retransmissions. Abort and return";
|
||||
res = SC_ERROR_INTERNAL;
|
||||
|
||||
cleanup_and_return:
|
||||
if (apdu->resp != wrapped.resp) free(wrapped.resp);
|
||||
if (msg)
|
||||
sc_log(ctx, msg);
|
||||
LOG_FUNC_RETURN(ctx, res);
|
||||
}
|
||||
|
||||
int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu)
|
||||
{
|
||||
int res = SC_SUCCESS;
|
||||
res = dnie_wrap_apdu(card, apdu);
|
||||
if (res <= 0) return res;
|
||||
return sc_transmit_apdu(card, apdu);
|
||||
sc_context_t *ctx;
|
||||
cwa_provider_t *provider = NULL;
|
||||
ctx=card->ctx;
|
||||
provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
|
||||
if ((provider->status.session.state == CWA_SM_ACTIVE) &&
|
||||
(card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)) {
|
||||
res = sc_transmit_apdu(card, apdu);
|
||||
LOG_TEST_RET(ctx, res, "Error in dnie_wrap_apdu process");
|
||||
res = cwa_decode_response(card, provider, apdu);
|
||||
LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process");
|
||||
}
|
||||
else
|
||||
res = sc_transmit_apdu(card, apdu);
|
||||
return res;
|
||||
}
|
||||
|
||||
void dnie_format_apdu(sc_card_t *card, sc_apdu_t *apdu,
|
||||
|
@ -1463,15 +1463,6 @@ int cwa_encode_apdu(sc_card_t * card,
|
||||
goto encode_end;
|
||||
}
|
||||
|
||||
/* call provider pre-operation method */
|
||||
if (provider->cwa_encode_pre_ops) {
|
||||
res = provider->cwa_encode_pre_ops(card, provider, from, to);
|
||||
if (res != SC_SUCCESS) {
|
||||
msg = "Encode APDU: provider pre_ops() failed";
|
||||
goto encode_end;
|
||||
}
|
||||
}
|
||||
|
||||
/* trace APDU before encoding process */
|
||||
cwa_trace_apdu(card, from, 0);
|
||||
|
||||
@ -1490,7 +1481,7 @@ int cwa_encode_apdu(sc_card_t * card,
|
||||
}
|
||||
|
||||
/* set up data on destination apdu */
|
||||
to->cse = SC_APDU_CASE_3_SHORT;
|
||||
to->cse = SC_APDU_CASE_4_SHORT;
|
||||
to->cla = from->cla | 0x0C; /* mark apdu as encoded */
|
||||
to->ins = from->ins;
|
||||
to->p1 = from->p1;
|
||||
@ -1588,15 +1579,6 @@ int cwa_encode_apdu(sc_card_t * card,
|
||||
to->data = apdubuf;
|
||||
to->datalen = apdulen;
|
||||
|
||||
/* call provider post-operation method */
|
||||
if (provider->cwa_encode_post_ops) {
|
||||
res = provider->cwa_encode_post_ops(card, provider, from, to);
|
||||
if (res != SC_SUCCESS) {
|
||||
msg = "Encode APDU: provider post_ops() failed";
|
||||
goto encode_end;
|
||||
}
|
||||
}
|
||||
|
||||
/* that's all folks */
|
||||
res = SC_SUCCESS;
|
||||
goto encode_end_apdu_valid;
|
||||
@ -1630,7 +1612,7 @@ encode_end_apdu_valid:
|
||||
*/
|
||||
int cwa_decode_response(sc_card_t * card,
|
||||
cwa_provider_t * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to)
|
||||
sc_apdu_t * apdu)
|
||||
{
|
||||
size_t i, j;
|
||||
cwa_tlv_t tlv_array[4];
|
||||
@ -1658,27 +1640,26 @@ int cwa_decode_response(sc_card_t * card,
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
/* check remaining arguments */
|
||||
if ((from == NULL) || (to == NULL) || (sm_session == NULL))
|
||||
if ((apdu == NULL) || (sm_session == NULL))
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_INITIALIZED);
|
||||
if (sm_session->state != CWA_SM_ACTIVE)
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL);
|
||||
|
||||
/* cwa14890 sect 9.3: check SW1 or SW2 for SM related errors */
|
||||
if (from->sw1 == 0x69) {
|
||||
if ((from->sw2 == 0x88) || (from->sw2 == 0x87)) {
|
||||
if (apdu->sw1 == 0x69) {
|
||||
if ((apdu->sw2 == 0x88) || (apdu->sw2 == 0x87)) {
|
||||
msg = "SM related errors in APDU response";
|
||||
res = SC_ERROR_SM_ENCRYPT_FAILED; /* tell driver to restart SM */
|
||||
goto response_decode_end;
|
||||
}
|
||||
}
|
||||
/* if response is null/empty assume unencoded apdu */
|
||||
if (!from->resp || (from->resplen == 0)) {
|
||||
if (!apdu->resp || (apdu->resplen == 0)) {
|
||||
sc_log(ctx, "Empty APDU response: assume not cwa encoded");
|
||||
memcpy(to, from, sizeof(sc_apdu_t));
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
/* checks if apdu response needs decoding by checking tags in response */
|
||||
switch (*from->resp) {
|
||||
switch (*apdu->resp) {
|
||||
case CWA_SM_PLAIN_TAG:
|
||||
case CWA_SM_CRYPTO_TAG:
|
||||
case CWA_SM_MAC_TAG:
|
||||
@ -1687,31 +1668,21 @@ int cwa_decode_response(sc_card_t * card,
|
||||
break; /* cwa tags found: continue decoding */
|
||||
default: /* else apdu response seems not to be cwa encoded */
|
||||
sc_log(card->ctx, "APDU Response seems not to be cwa encoded");
|
||||
memcpy(to, from, sizeof(sc_apdu_t));
|
||||
return SC_SUCCESS; /* let process continue */
|
||||
}
|
||||
|
||||
/* call provider pre-operation method */
|
||||
if (provider->cwa_decode_pre_ops) {
|
||||
res = provider->cwa_decode_pre_ops(card, provider, from, to);
|
||||
if (res != SC_SUCCESS) {
|
||||
sc_log(ctx, "Decode APDU: provider pre_ops() failed");
|
||||
LOG_FUNC_RETURN(ctx, res);
|
||||
}
|
||||
}
|
||||
|
||||
/* parse response to find TLV's data and check results */
|
||||
memset(tlv_array, 0, 4 * sizeof(cwa_tlv_t));
|
||||
/* create buffer and copy data into */
|
||||
buffer = calloc(from->resplen, sizeof(u8));
|
||||
buffer = calloc(apdu->resplen, sizeof(u8));
|
||||
if (!buffer) {
|
||||
msg = "Cannot allocate space for response buffer";
|
||||
res = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto response_decode_end;
|
||||
}
|
||||
memcpy(buffer, from->resp, from->resplen);
|
||||
memcpy(buffer, apdu->resp, apdu->resplen);
|
||||
|
||||
res = cwa_parse_tlv(card, buffer, from->resplen, tlv_array);
|
||||
res = cwa_parse_tlv(card, buffer, apdu->resplen, tlv_array);
|
||||
if (res != SC_SUCCESS) {
|
||||
msg = "Error in TLV parsing";
|
||||
goto response_decode_end;
|
||||
@ -1737,7 +1708,7 @@ int cwa_decode_response(sc_card_t * card,
|
||||
|
||||
/* compose buffer to evaluate mac */
|
||||
|
||||
/* reserve enought space for data+status+padding */
|
||||
/* reserve enough space for data+status+padding */
|
||||
ccbuf =
|
||||
calloc(e_tlv->buflen + s_tlv->buflen + p_tlv->buflen + 8,
|
||||
sizeof(u8));
|
||||
@ -1764,12 +1735,9 @@ int cwa_decode_response(sc_card_t * card,
|
||||
}
|
||||
memcpy(ccbuf + cclen, s_tlv->buf, s_tlv->buflen);
|
||||
cclen += s_tlv->buflen;
|
||||
to->sw1 = s_tlv->data[0];
|
||||
to->sw2 = s_tlv->data[1];
|
||||
} else { /* if no response status tag, use sw1 and sw2 from apdu */
|
||||
to->sw1 = from->sw1;
|
||||
to->sw2 = from->sw2;
|
||||
}
|
||||
apdu->sw1 = s_tlv->data[0];
|
||||
apdu->sw2 = s_tlv->data[1];
|
||||
} /* if no response status tag, use sw1 and sw2 from apdu */
|
||||
/* add iso7816 padding */
|
||||
cwa_iso7816_padding(ccbuf, &cclen);
|
||||
|
||||
@ -1809,29 +1777,23 @@ int cwa_decode_response(sc_card_t * card,
|
||||
|
||||
/* allocate response buffer */
|
||||
resplen = 10 + MAX(p_tlv->len, e_tlv->len); /* estimate response buflen */
|
||||
if (to->resp) { /* if response apdu provides buffer, try to use it */
|
||||
if (to->resplen < resplen) {
|
||||
msg =
|
||||
"Provided buffer has not enough size to store response";
|
||||
res = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto response_decode_end;
|
||||
}
|
||||
} else { /* buffer not provided: create and assing to response apdu */
|
||||
to->resp = calloc(resplen, sizeof(u8));
|
||||
if (!to->resp) {
|
||||
if (apdu->resplen < resplen) {
|
||||
free(apdu->resp);
|
||||
apdu->resp = calloc(resplen, sizeof(u8));
|
||||
if (!apdu->resp) {
|
||||
msg = "Cannot allocate buffer to store response";
|
||||
res = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto response_decode_end;
|
||||
}
|
||||
}
|
||||
to->resplen = resplen;
|
||||
apdu->resplen = resplen;
|
||||
|
||||
/* fill destination response apdu buffer with data */
|
||||
|
||||
/* if plain data, just copy TLV data into apdu response */
|
||||
if (p_tlv->buf) { /* plain data */
|
||||
memcpy(to->resp, p_tlv->data, p_tlv->len);
|
||||
to->resplen = p_tlv->len;
|
||||
memcpy(apdu->resp, p_tlv->data, p_tlv->len);
|
||||
apdu->resplen = p_tlv->len;
|
||||
}
|
||||
|
||||
/* if encoded data, decode and store into apdu response */
|
||||
@ -1856,33 +1818,24 @@ int cwa_decode_response(sc_card_t * card,
|
||||
&k2);
|
||||
/* decrypt into response buffer
|
||||
* by using 3DES CBC by mean of kenc and iv={0,...0} */
|
||||
DES_ede3_cbc_encrypt(&e_tlv->data[1], to->resp, e_tlv->len - 1,
|
||||
DES_ede3_cbc_encrypt(&e_tlv->data[1], apdu->resp, e_tlv->len - 1,
|
||||
&k1, &k2, &k1, &iv, DES_DECRYPT);
|
||||
to->resplen = e_tlv->len - 1;
|
||||
apdu->resplen = e_tlv->len - 1;
|
||||
/* remove iso padding from response length */
|
||||
for (; (to->resplen > 0) && *(to->resp + to->resplen - 1) == 0x00; to->resplen--) ; /* empty loop */
|
||||
for (; (apdu->resplen > 0) && *(apdu->resp + apdu->resplen - 1) == 0x00; apdu->resplen--) ; /* empty loop */
|
||||
|
||||
if (*(to->resp + to->resplen - 1) != 0x80) { /* check padding byte */
|
||||
if (*(apdu->resp + apdu->resplen - 1) != 0x80) { /* check padding byte */
|
||||
msg =
|
||||
"Decrypted TLV has no 0x80 iso padding indicator!";
|
||||
res = SC_ERROR_INVALID_DATA;
|
||||
goto response_decode_end;
|
||||
}
|
||||
/* everything ok: remove ending 0x80 from response */
|
||||
to->resplen--;
|
||||
apdu->resplen--;
|
||||
}
|
||||
|
||||
else
|
||||
to->resplen = 0; /* neither plain, nor encoded data */
|
||||
|
||||
/* call provider post-operation method */
|
||||
if (provider->cwa_decode_post_ops) {
|
||||
res = provider->cwa_decode_post_ops(card, provider, from, to);
|
||||
if (res != SC_SUCCESS) {
|
||||
sc_log(ctx, "Decode APDU: provider post_ops() failed");
|
||||
goto response_decode_end;
|
||||
}
|
||||
}
|
||||
apdu->resplen = 0; /* neither plain, nor encoded data */
|
||||
|
||||
/* that's all folks */
|
||||
res = SC_SUCCESS;
|
||||
@ -1895,7 +1848,7 @@ int cwa_decode_response(sc_card_t * card,
|
||||
if (msg) {
|
||||
sc_log(ctx, msg);
|
||||
} else {
|
||||
cwa_trace_apdu(card, to, 1);
|
||||
cwa_trace_apdu(card, apdu, 1);
|
||||
} /* trace apdu response */
|
||||
LOG_FUNC_RETURN(ctx, res);
|
||||
}
|
||||
@ -1989,36 +1942,6 @@ static int default_get_sn_icc(sc_card_t * card, u8 ** buf)
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/************** operations related with APDU encoding ******************/
|
||||
|
||||
/* pre and post operations */
|
||||
static int default_encode_pre_ops(sc_card_t * card, cwa_provider_t * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to)
|
||||
{
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int default_encode_post_ops(sc_card_t * card, cwa_provider_t * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to)
|
||||
{
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
/************** operations related APDU response decoding **************/
|
||||
|
||||
/* pre and post operations */
|
||||
static int default_decode_pre_ops(sc_card_t * card, cwa_provider_t * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to)
|
||||
{
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int default_decode_post_ops(sc_card_t * card, cwa_provider_t * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to)
|
||||
{
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static cwa_provider_t default_cwa_provider = {
|
||||
|
||||
/************ data related with SM operations *************************/
|
||||
@ -2106,17 +2029,7 @@ static cwa_provider_t default_cwa_provider = {
|
||||
/* Get ICC Serial Number */
|
||||
default_get_sn_icc,
|
||||
|
||||
/************** operations related with APDU encoding ******************/
|
||||
|
||||
/* pre and post operations */
|
||||
default_encode_pre_ops,
|
||||
default_encode_post_ops,
|
||||
|
||||
/************** operations related APDU response decoding **************/
|
||||
|
||||
/* pre and post operations */
|
||||
default_decode_pre_ops,
|
||||
default_decode_post_ops,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -274,61 +274,7 @@ typedef struct cwa_provider_st {
|
||||
*/
|
||||
int (*cwa_get_sn_icc) (sc_card_t * card, u8 ** buf);
|
||||
|
||||
/************** operations related with APDU encoding ******************/
|
||||
|
||||
/**
|
||||
* Operation to be done before any APDU encode procedure.
|
||||
*
|
||||
* @param card Pointer to card driver data structure
|
||||
* @param provider pointer to cwa1890 SM provider
|
||||
* @param from APDU to be encoded
|
||||
* @param to resulting APDU to be sent to encode procedure
|
||||
* @return SC_SUCCESS if OK, else error code
|
||||
*/
|
||||
int (*cwa_encode_pre_ops) (sc_card_t * card,
|
||||
struct cwa_provider_st * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to);
|
||||
|
||||
/**
|
||||
* Operation to be done after APDU encode process finished ok.
|
||||
*
|
||||
* @param card Pointer to card driver data structure
|
||||
* @param provider pointer to cwa1890 SM provider
|
||||
* @param from encoded APDU
|
||||
* @param to resulting encoded APDU to be returned to libopensc
|
||||
* @return SC_SUCCESS if OK, else error code
|
||||
*/
|
||||
int (*cwa_encode_post_ops) (sc_card_t * card,
|
||||
struct cwa_provider_st * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to);
|
||||
|
||||
/************** operations related APDU response decoding **************/
|
||||
|
||||
/**
|
||||
* Operation to be done before any APDU Response decode procedure.
|
||||
*
|
||||
* @param card Pointer to card driver data structure
|
||||
* @param provider pointer to cwa1890 SM provider
|
||||
* @param from APDU Response to be decoded
|
||||
* @param to resulting APDU response to be sent to decode procedure
|
||||
* @return SC_SUCCESS if OK, else error code
|
||||
*/
|
||||
int (*cwa_decode_pre_ops) (sc_card_t * card,
|
||||
struct cwa_provider_st * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to);
|
||||
|
||||
/**
|
||||
* Operation to be done after APDU Response decode process finished ok.
|
||||
*
|
||||
* @param card Pointer to card driver data structure
|
||||
* @param provider pointer to cwa1890 SM provider
|
||||
* @param from decoded APDU Response
|
||||
* @param to resulting APDU Response to be returned to libopensc
|
||||
* @return SC_SUCCESS if OK, else error code
|
||||
*/
|
||||
int (*cwa_decode_post_ops) (sc_card_t * card,
|
||||
struct cwa_provider_st * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to);
|
||||
|
||||
} cwa_provider_t;
|
||||
|
||||
/************************** external function prototypes ******************/
|
||||
@ -359,13 +305,12 @@ extern int cwa_create_secure_channel(sc_card_t * card,
|
||||
*
|
||||
* @param card card info structure
|
||||
* @param provider cwa provider data to handle SM channel
|
||||
* @param from apdu to be decoded
|
||||
* @param to where to store decoded apdu
|
||||
* @param apdu apdu to be decoded
|
||||
* @return SC_SUCCESS if ok; else error code
|
||||
*/
|
||||
extern int cwa_decode_response(sc_card_t * card,
|
||||
cwa_provider_t * provider,
|
||||
sc_apdu_t * from, sc_apdu_t * to);
|
||||
sc_apdu_t * apdu);
|
||||
|
||||
/**
|
||||
* Encode an APDU.
|
||||
|
Loading…
Reference in New Issue
Block a user