[pkg-opensc-commit] [opensc] 01/295: DNIe. Removing all memory leaks and using SM wrapping and unwrapping.
Eric Dorland
eric at moszumanska.debian.org
Sat Jun 24 21:11:10 UTC 2017
This is an automated email from the git hooks/post-receive script.
eric pushed a commit to branch master
in repository opensc.
commit 1dd501a705575a8041e62bd3822896c8b104d79f
Author: German Blanco <german.blanco at gmail.com>
Date: Sun Feb 28 08:13:45 2016 +0100
DNIe. Removing all memory leaks and using SM wrapping and unwrapping.
---
src/libopensc/card-dnie.c | 142 ++++++++++++++++++++-------
src/libopensc/cwa-dnie.c | 242 ++++------------------------------------------
src/libopensc/cwa14890.c | 143 ++++++---------------------
src/libopensc/cwa14890.h | 61 +-----------
4 files changed, 158 insertions(+), 430 deletions(-)
diff --git a/src/libopensc/card-dnie.c b/src/libopensc/card-dnie.c
index e442cb4..cc15be0 100644
--- a/src/libopensc/card-dnie.c
+++ b/src/libopensc/card-dnie.c
@@ -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
diff --git a/src/libopensc/cwa-dnie.c b/src/libopensc/cwa-dnie.c
index 6cabcd3..311d499 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 dnie_transmit_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);
- }
+ 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");
}
- 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);
+ 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 9d3e1a8..46594dd 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 5cebe72..b55d3b5 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.
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git
More information about the pkg-opensc-commit
mailing list