Fixing part of the memory allocation problems in DNIe module.

This commit is contained in:
German Blanco 2015-05-26 21:44:13 +02:00
parent b48fa70308
commit 76517b7d43
4 changed files with 94 additions and 69 deletions

View File

@ -293,7 +293,7 @@ data_found:
static int dnie_get_info(sc_card_t * card, char *data[])
{
sc_file_t *file = NULL;
sc_path_t *path = NULL;
sc_path_t path;
u8 *buffer = NULL;
size_t bufferlen = 0;
char *msg = NULL;
@ -309,14 +309,8 @@ static int dnie_get_info(sc_card_t * card, char *data[])
/* phase 1: get DNIe number, Name and GivenName */
/* read EF(CDF) at 3F0050156004 */
path = (sc_path_t *) calloc(1, sizeof(sc_path_t));
if (!path) {
msg = "Cannot allocate path data for EF(CDF) read";
res = SC_ERROR_OUT_OF_MEMORY;
goto get_info_end;
}
sc_format_path("3F0050156004", path);
res = dnie_read_file(card, path, &file, &buffer, &bufferlen);
sc_format_path("3F0050156004", &path);
res = dnie_read_file(card, &path, &file, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot read EF(CDF)";
goto get_info_end;
@ -334,7 +328,7 @@ static int dnie_get_info(sc_card_t * card, char *data[])
}
/* phase 2: get IDESP */
sc_format_path("3F000006", path);
sc_format_path("3F000006", &path);
if (file) {
sc_file_free(file);
file = NULL;
@ -344,7 +338,7 @@ static int dnie_get_info(sc_card_t * card, char *data[])
buffer=NULL;
bufferlen=0;
}
res = dnie_read_file(card, path, &file, &buffer, &bufferlen);
res = dnie_read_file(card, &path, &file, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
data[3]=NULL;
goto get_info_ph3;
@ -359,7 +353,7 @@ static int dnie_get_info(sc_card_t * card, char *data[])
get_info_ph3:
/* phase 3: get DNIe software version */
sc_format_path("3F002F03", path);
sc_format_path("3F002F03", &path);
if (file) {
sc_file_free(file);
file = NULL;
@ -373,7 +367,7 @@ get_info_ph3:
* Some old DNIe cards seems not to include SW version file,
* so let this code fail without notice
*/
res = dnie_read_file(card, path, &file, &buffer, &bufferlen);
res = dnie_read_file(card, &path, &file, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot read DNIe Version EF";
data[4]=NULL;
@ -395,10 +389,12 @@ get_info_ph3:
get_info_end:
if (file) {
sc_file_free(file);
free(buffer);
file = NULL;
buffer = NULL;
bufferlen = 0;
}
if (buffer) {
free(buffer);
buffer=NULL;
bufferlen=0;
}
if (msg)
sc_log(card->ctx,msg);
@ -905,6 +901,8 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa
if (file == NULL)
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
res = card->ops->process_fci(card, file, apdu.resp + 2, apdu.resp[1]);
if (*file_out != NULL)
sc_file_free(*file_out);
*file_out = file;
LOG_FUNC_RETURN(ctx, res);
}

View File

@ -265,6 +265,8 @@ int dnie_read_file(sc_card_t * card,
res = SC_SUCCESS;
goto dnie_read_file_end;
dnie_read_file_err:
if (data)
free(data);
if (*file) {
sc_file_free(*file);
*file = NULL;
@ -289,39 +291,37 @@ int dnie_read_file(sc_card_t * card,
static int dnie_read_certificate(sc_card_t * card, char *certpath, X509 ** cert)
{
sc_file_t *file = NULL;
sc_path_t *path = NULL;
u8 *buffer = NULL;
sc_path_t path;
u8 *buffer = NULL, *buffer2 = NULL;
char *msg = NULL;
size_t bufferlen = 0;
int res = SC_SUCCESS;
LOG_FUNC_CALLED(card->ctx);
path = (sc_path_t *) calloc(1, sizeof(sc_path_t));
if (!path) {
msg = "Cannot allocate path data for cert read";
res = SC_ERROR_OUT_OF_MEMORY;
goto read_cert_end;
}
sc_format_path(certpath, path);
res = dnie_read_file(card, path, &file, &buffer, &bufferlen);
sc_format_path(certpath, &path);
res = dnie_read_file(card, &path, &file, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot get intermediate CA cert";
goto read_cert_end;
}
*cert = d2i_X509(NULL, (const unsigned char **)&buffer, bufferlen);
buffer2 = buffer;
*cert = d2i_X509(NULL, (const unsigned char **)&buffer2, bufferlen);
if (*cert == NULL) { /* received data is not a certificate */
res = SC_ERROR_OBJECT_NOT_VALID;
msg = "Readed data is not a certificate";
msg = "Read data is not a certificate";
goto read_cert_end;
}
res = SC_SUCCESS;
read_cert_end:
if (buffer) {
free(buffer);
buffer = NULL;
bufferlen = 0;
}
if (file) {
sc_file_free(file);
file = NULL;
buffer = NULL;
bufferlen = 0;
}
if (msg)
sc_log(card->ctx, msg);
@ -690,7 +690,7 @@ cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card)
static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
{
u8 buf[2048]; /* use for store partial le responses */
u8 buf[2*SC_MAX_APDU_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))
@ -711,8 +711,10 @@ static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
if (tmp == SC_APDU_CASE_3_SHORT)
apdu->cse = SC_APDU_CASE_4_SHORT;
if (apdu->resplen == 0) { /* no response buffer: create */
apdu->resp = buf;
apdu->resplen = 2048;
apdu->resp = calloc(1, 2*SC_MAX_APDU_BUFFER_SIZE);
if (apdu->resp == NULL)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
apdu->resplen = 2*SC_MAX_APDU_BUFFER_SIZE;
apdu->le = card->max_recv_size;
}
}
@ -724,17 +726,12 @@ static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
size_t e_txlen = 0;
size_t index = 0;
sc_apdu_t *e_apdu = NULL;
u8 *e_tx = NULL;
sc_apdu_t e_apdu;
u8 e_tx[2*SC_MAX_APDU_BUFFER_SIZE];
/* envelope needed */
sc_log(card->ctx, "envelope tx required: lc:%d", apdu->lc);
e_apdu = calloc(1, sizeof(sc_apdu_t)); /* enveloped apdu */
e_tx = calloc(7 + apdu->datalen, sizeof(u8)); /* enveloped data */
if (!e_apdu || !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;
@ -753,35 +750,37 @@ static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
index, len);
/* compose envelope apdu command */
sc_format_apdu(card, e_apdu, apdu->cse, 0xC2, 0x00,
0x00);
e_apdu->cla = 0x90; /* propietary CLA */
e_apdu->data = e_tx + index;
e_apdu->lc = len;
e_apdu->datalen = len;
e_apdu->le = apdu->le;
e_apdu->resp = apdu->resp;
e_apdu->resplen = apdu->resplen;
sc_format_apdu(card, &e_apdu, apdu->cse, 0xC2, 0x00, 0x00);
e_apdu.cla = 0x90; /* propietary CLA */
e_apdu.data = e_tx + index;
e_apdu.lc = len;
e_apdu.datalen = len;
e_apdu.le = apdu->le;
e_apdu.resp = apdu->resp;
e_apdu.resplen = apdu->resplen;
/* 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 (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;
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);
res = sc_transmit_apdu(card, &e_apdu);
LOG_TEST_RET(card->ctx, res,
"Error in envelope() send apdu");
} /* for */
/* last apdu sent contains response to enveloped cmd */
apdu->resp = e_apdu->resp;
apdu->resplen = e_apdu->resplen;
apdu->resp = calloc(1, 2*SC_MAX_APDU_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);
@ -817,6 +816,7 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
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;
@ -831,13 +831,18 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
wrapped.resp = NULL;
wrapped.resplen = 0; /* let get_response() assign space */
res = cwa_encode_apdu(card, provider, apdu, &wrapped);
LOG_TEST_RET(ctx, res,
"Error in cwa_encode_apdu process");
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 */
LOG_TEST_RET(ctx, res, "Error in dnie_transmit_apdu process");
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);
@ -852,7 +857,10 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
/* SM was active: force restart SM and retry */
case CWA_SM_ACTIVE:
res=cwa_create_secure_channel(card, provider, CWA_SM_COLD);
LOG_TEST_RET(ctx,res,"Cannot re-enable SM");
if (res != SC_SUCCESS) {
msg = "Cannot re-enable SM";
goto cleanup_and_return;
}
continue;
}
}
@ -862,15 +870,24 @@ static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
apdu->resp = NULL;
apdu->resplen = 0; /* let cwa_decode_response() eval & create size */
res = cwa_decode_response(card, provider, &wrapped, apdu);
LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process");
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);
}
LOG_FUNC_RETURN(ctx, res);
}
sc_log(ctx,"Too many retransmissions. Abort and return");
LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
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)

View File

@ -1397,6 +1397,10 @@ int cwa_create_secure_channel(sc_card_t * card,
/* arriving here means ok: cleanup */
res = SC_SUCCESS;
csc_end:
if (icc_cert)
X509_free(icc_cert);
if (ca_cert)
X509_free(ca_cert);
if (icc_pubkey)
EVP_PKEY_free(icc_pubkey);
if (ifd_privkey)

View File

@ -42,13 +42,19 @@ int dump_ef(sc_card_t * card, const char *path, u8 * buf, size_t * buf_len)
{
int rv;
sc_file_t *file = sc_file_new();
sc_format_path(path, &file->path);
rv = sc_select_file(card, &file->path, &file);
if (rv < 0)
sc_path_t scpath;
sc_format_path(path, &scpath);
rv = sc_select_file(card, &scpath, &file);
if (rv < 0) {
sc_file_free(file);
return rv;
if (file->size > *buf_len)
}
if (file->size > *buf_len) {
sc_file_free(file);
return SC_ERROR_BUFFER_TOO_SMALL;
}
rv = sc_read_binary(card, 0, buf, file->size, 0);
sc_file_free(file);
if (rv < 0)
return rv;
*buf_len = rv;