From 1dd501a705575a8041e62bd3822896c8b104d79f Mon Sep 17 00:00:00 2001 From: German Blanco Date: Sun, 28 Feb 2016 08:13:45 +0100 Subject: [PATCH] DNIe. Removing all memory leaks and using SM wrapping and unwrapping. --- src/libopensc/card-dnie.c | 142 +++++++++++++++++----- src/libopensc/cwa-dnie.c | 250 ++++---------------------------------- src/libopensc/cwa14890.c | 143 +++++----------------- src/libopensc/cwa14890.h | 61 +--------- 4 files changed, 162 insertions(+), 434 deletions(-) diff --git a/src/libopensc/card-dnie.c b/src/libopensc/card-dnie.c index e442cb48..cc15be0a 100644 --- a/src/libopensc/card-dnie.c +++ b/src/libopensc/card-dnie.c @@ -53,6 +53,9 @@ #ifdef __APPLE__ #include #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 diff --git a/src/libopensc/cwa-dnie.c b/src/libopensc/cwa-dnie.c index 6cabcd3f..311d499a 100644 --- a/src/libopensc/cwa-dnie.c +++ b/src/libopensc/cwa-dnie.c @@ -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, diff --git a/src/libopensc/cwa14890.c b/src/libopensc/cwa14890.c index 9d3e1a86..46594ddc 100644 --- a/src/libopensc/cwa14890.c +++ b/src/libopensc/cwa14890.c @@ -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, }; /** diff --git a/src/libopensc/cwa14890.h b/src/libopensc/cwa14890.h index 5cebe728..b55d3b58 100644 --- a/src/libopensc/cwa14890.h +++ b/src/libopensc/cwa14890.h @@ -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.