DNIe. Removing all memory leaks and using SM wrapping and unwrapping.

This commit is contained in:
German Blanco 2016-02-28 08:13:45 +01:00
parent b8c3722bf5
commit 1dd501a705
4 changed files with 162 additions and 434 deletions

View File

@ -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

View File

@ -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,

View File

@ -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,
};
/**

View File

@ -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.