adjust send/receive size accoriding to card capabilities
This commit is contained in:
parent
d00d7b3498
commit
3f442c5608
|
@ -29,6 +29,43 @@
|
||||||
#include "asn1.h"
|
#include "asn1.h"
|
||||||
#include "iso7816.h"
|
#include "iso7816.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void fixup_transceive_length(const struct sc_card *card,
|
||||||
|
struct sc_apdu *apdu)
|
||||||
|
{
|
||||||
|
size_t max_send_size;
|
||||||
|
size_t max_recv_size;
|
||||||
|
|
||||||
|
assert(card != NULL && apdu != NULL);
|
||||||
|
|
||||||
|
max_send_size = card->max_send_size;
|
||||||
|
max_recv_size = card->max_recv_size;
|
||||||
|
|
||||||
|
if (card->caps & SC_CARD_CAP_APDU_EXT) {
|
||||||
|
if (!max_send_size)
|
||||||
|
max_send_size = 65535;
|
||||||
|
if (!max_recv_size)
|
||||||
|
max_recv_size = 65536;
|
||||||
|
} else {
|
||||||
|
if (!max_send_size)
|
||||||
|
max_send_size = 255;
|
||||||
|
if (!max_recv_size)
|
||||||
|
max_recv_size = 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apdu->lc > max_send_size) {
|
||||||
|
/* The lower layers will automatically do chaining */
|
||||||
|
apdu->flags |= SC_APDU_FLAGS_CHAINING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apdu->le > max_recv_size) {
|
||||||
|
/* The lower layers will automatically do a GET RESPONSE, if possible.
|
||||||
|
* All other workarounds must be carried out by the upper layers. */
|
||||||
|
apdu->le = max_recv_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct sc_card_error iso7816_errors[] = {
|
static const struct sc_card_error iso7816_errors[] = {
|
||||||
{ 0x6200, SC_ERROR_CARD_CMD_FAILED, "Warning: no information given, non-volatile memory is unchanged" },
|
{ 0x6200, SC_ERROR_CARD_CMD_FAILED, "Warning: no information given, non-volatile memory is unchanged" },
|
||||||
{ 0x6281, SC_ERROR_CORRUPTED_DATA, "Part of returned data may be corrupted" },
|
{ 0x6281, SC_ERROR_CORRUPTED_DATA, "Part of returned data may be corrupted" },
|
||||||
|
@ -121,12 +158,12 @@ iso7816_read_binary(struct sc_card *card, unsigned int idx, u8 *buf, size_t coun
|
||||||
return SC_ERROR_OFFSET_TOO_LARGE;
|
return SC_ERROR_OFFSET_TOO_LARGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(count <= (card->max_recv_size > 0 ? card->max_recv_size : 256));
|
|
||||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xB0, (idx >> 8) & 0x7F, idx & 0xFF);
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xB0, (idx >> 8) & 0x7F, idx & 0xFF);
|
||||||
apdu.le = count;
|
apdu.le = count;
|
||||||
apdu.resplen = count;
|
apdu.resplen = count;
|
||||||
apdu.resp = buf;
|
apdu.resp = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(ctx, r, "APDU transmit failed");
|
||||||
if (apdu.resplen == 0)
|
if (apdu.resplen == 0)
|
||||||
|
@ -166,6 +203,7 @@ iso7816_read_record(struct sc_card *card,
|
||||||
apdu.resplen = count;
|
apdu.resplen = count;
|
||||||
apdu.resp = buf;
|
apdu.resp = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
if (apdu.resplen == 0)
|
if (apdu.resplen == 0)
|
||||||
|
@ -191,6 +229,7 @@ iso7816_write_record(struct sc_card *card, unsigned int rec_nr,
|
||||||
apdu.datalen = count;
|
apdu.datalen = count;
|
||||||
apdu.data = buf;
|
apdu.data = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||||
|
@ -214,6 +253,7 @@ iso7816_append_record(struct sc_card *card,
|
||||||
apdu.datalen = count;
|
apdu.datalen = count;
|
||||||
apdu.data = buf;
|
apdu.data = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||||
|
@ -239,6 +279,7 @@ iso7816_update_record(struct sc_card *card, unsigned int rec_nr,
|
||||||
apdu.datalen = count;
|
apdu.datalen = count;
|
||||||
apdu.data = buf;
|
apdu.data = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||||
|
@ -255,8 +296,6 @@ iso7816_write_binary(struct sc_card *card,
|
||||||
struct sc_apdu apdu;
|
struct sc_apdu apdu;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(count <= (card->max_send_size > 0 ? card->max_send_size : 255));
|
|
||||||
|
|
||||||
if (idx > 0x7fff) {
|
if (idx > 0x7fff) {
|
||||||
sc_log(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx);
|
sc_log(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx);
|
||||||
return SC_ERROR_OFFSET_TOO_LARGE;
|
return SC_ERROR_OFFSET_TOO_LARGE;
|
||||||
|
@ -268,6 +307,7 @@ iso7816_write_binary(struct sc_card *card,
|
||||||
apdu.datalen = count;
|
apdu.datalen = count;
|
||||||
apdu.data = buf;
|
apdu.data = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||||
|
@ -284,8 +324,6 @@ iso7816_update_binary(struct sc_card *card,
|
||||||
struct sc_apdu apdu;
|
struct sc_apdu apdu;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(count <= (card->max_send_size > 0 ? card->max_send_size : 255));
|
|
||||||
|
|
||||||
if (idx > 0x7fff) {
|
if (idx > 0x7fff) {
|
||||||
sc_log(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx);
|
sc_log(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx);
|
||||||
return SC_ERROR_OFFSET_TOO_LARGE;
|
return SC_ERROR_OFFSET_TOO_LARGE;
|
||||||
|
@ -296,6 +334,7 @@ iso7816_update_binary(struct sc_card *card,
|
||||||
apdu.datalen = count;
|
apdu.datalen = count;
|
||||||
apdu.data = buf;
|
apdu.data = buf;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||||
|
@ -829,6 +868,8 @@ iso7816_compute_signature(struct sc_card *card,
|
||||||
apdu.data = data;
|
apdu.data = data;
|
||||||
apdu.lc = datalen;
|
apdu.lc = datalen;
|
||||||
apdu.datalen = datalen;
|
apdu.datalen = datalen;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
|
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
|
||||||
|
@ -864,19 +905,15 @@ iso7816_decipher(struct sc_card *card,
|
||||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
|
||||||
apdu.resp = out;
|
apdu.resp = out;
|
||||||
apdu.resplen = outlen;
|
apdu.resplen = outlen;
|
||||||
/* if less than 256 bytes are expected than set Le to 0x00
|
apdu.le = outlen;
|
||||||
* to tell the card the we want everything available (note: we
|
|
||||||
* always have Le <= crgram_len) */
|
|
||||||
apdu.le = (outlen >= 256 && crgram_len < 256) ? 256 : outlen;
|
|
||||||
/* Use APDU chaining with 2048bit RSA keys if the card does not do extended APDU-s */
|
|
||||||
if ((crgram_len+1 > 255) && !(card->caps & SC_CARD_CAP_APDU_EXT))
|
|
||||||
apdu.flags |= SC_APDU_FLAGS_CHAINING;
|
|
||||||
|
|
||||||
sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
|
sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
|
||||||
memcpy(sbuf + 1, crgram, crgram_len);
|
memcpy(sbuf + 1, crgram, crgram_len);
|
||||||
apdu.data = sbuf;
|
apdu.data = sbuf;
|
||||||
apdu.lc = crgram_len + 1;
|
apdu.lc = crgram_len + 1;
|
||||||
apdu.datalen = crgram_len + 1;
|
apdu.datalen = crgram_len + 1;
|
||||||
|
|
||||||
|
fixup_transceive_length(card, &apdu);
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
sc_mem_clear(sbuf, crgram_len + 1);
|
sc_mem_clear(sbuf, crgram_len + 1);
|
||||||
free(sbuf);
|
free(sbuf);
|
||||||
|
|
Loading…
Reference in New Issue