diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index 45c46a61..c22901dd 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -1302,6 +1302,7 @@ static int do_apdu(int argc, char **argv) u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; size_t len, len0, r, ii; + int cse = 0; if (argc < 1) { puts("Usage: apdu [apdu:hex:codes:...]"); @@ -1327,42 +1328,72 @@ static int do_apdu(int argc, char **argv) apdu.p1 = *p++; apdu.p2 = *p++; len -= 4; - if (len > 1) { - apdu.lc = *p++; - len--; - memcpy(sbuf, p, apdu.lc); - apdu.data = sbuf; - apdu.datalen = apdu.lc; - if (len < apdu.lc) { - printf("APDU too short (need %lu bytes)\n", - (unsigned long) apdu.lc - len); - return 1; - } - len -= apdu.lc; - p += apdu.lc; - if (len) { - apdu.le = *p++; - if (apdu.le == 0) - apdu.le = 256; - len--; - apdu.cse = SC_APDU_CASE_4_SHORT; - } else { - apdu.cse = SC_APDU_CASE_3_SHORT; - } - if (len) { - printf("APDU too long (%lu bytes extra)\n", - (unsigned long) len); - return 1; - } - } else if (len == 1) { - apdu.le = *p++; - if (apdu.le == 0) - apdu.le = 256; - len--; - apdu.cse = SC_APDU_CASE_2_SHORT; - } else { + + if (len == 0) { apdu.cse = SC_APDU_CASE_1; } + else { + size_t size = 0; + + if ((*p == 0) && (len >= 3)) { + cse |= SC_APDU_EXT; + p++; + size = (*p++) << 8; + size += *p++; + len -= 3; + } + else { + size = *p++; + len--; + } + if (len == 0) { + apdu.le = (size == 0) ? 256 : size; + if ((apdu.le == 0) && (cse & SC_APDU_EXT)) + apdu.le <<= 8; + apdu.cse = SC_APDU_CASE_2_SHORT | cse; + } + else { + apdu.lc = size; + if (len < apdu.lc) { + printf("APDU too short (need %lu bytes)\n", + (unsigned long) apdu.lc - len); + return 1; + } + memcpy(sbuf, p, apdu.lc); + apdu.data = sbuf; + apdu.datalen = apdu.lc; + len -= apdu.lc; + p += apdu.lc; + if (len == 0) { + apdu.cse = SC_APDU_CASE_3_SHORT | cse; + } + else { + apdu.le = 0; + if (cse & SC_APDU_EXT) { + if (len < 2) { + printf("APDU too short (need %lu bytes)\n", + (unsigned long) apdu.lc - len); + return 1; + } + size = (*p++) << 8; + size += *p++; + len -= 2; + apdu.le = (size == 0) ? 65536 : size; + } + else { + size = *p++; + len--; + apdu.le = (size == 0) ? 256 : size; + } + apdu.cse = SC_APDU_CASE_4_SHORT | cse; + if (len) { + printf("APDU too long (%lu bytes extra)\n", + (unsigned long) len); + return 1; + } + } + } + } apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c index f17dfa1f..4801b860 100644 --- a/src/tools/opensc-tool.c +++ b/src/tools/opensc-tool.c @@ -496,6 +496,7 @@ static int send_apdu(void) rbuf[SC_MAX_APDU_BUFFER_SIZE], *p; size_t len, len0, r; int c; + int cse = 0; for (c = 0; c < opt_apdu_count; c++) { len0 = sizeof(buf); @@ -514,40 +515,73 @@ static int send_apdu(void) apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); len -= 4; - if (len > 1) { - apdu.lc = *p++; - len--; - memcpy(sbuf, p, apdu.lc); - apdu.data = sbuf; - apdu.datalen = apdu.lc; - if (len < apdu.lc) { - fprintf(stderr, "APDU too short (need %lu bytes).\n", - (unsigned long) apdu.lc-len); - return 2; - } - len -= apdu.lc; - p += apdu.lc; - if (len) { - apdu.le = *p++; - if (apdu.le == 0) - apdu.le = 256; - len--; - apdu.cse = SC_APDU_CASE_4_SHORT; - } else - apdu.cse = SC_APDU_CASE_3_SHORT; - if (len) { - fprintf(stderr, "APDU too long (%lu bytes extra).\n", - (unsigned long) len); - return 2; - } - } else if (len == 1) { - apdu.le = *p++; - if (apdu.le == 0) - apdu.le = 256; - len--; - apdu.cse = SC_APDU_CASE_2_SHORT; - } else + + if (len == 0) { apdu.cse = SC_APDU_CASE_1; + } + else { + size_t size = 0; + + if ((*p == 0) && (len >= 3)) { + cse |= SC_APDU_EXT; + p++; + size = (*p++) << 8; + size += *p++; + len -= 3; + } + else { + size = *p++; + len--; + } + if (len == 0) { + apdu.le = (size == 0) ? 256 : size; + if ((apdu.le == 0) && (cse & SC_APDU_EXT)) + apdu.le <<= 8; + apdu.cse = SC_APDU_CASE_2_SHORT | cse; + } + else { + apdu.lc = size; + if (len < apdu.lc) { + printf("APDU too short (need %lu bytes)\n", + (unsigned long) apdu.lc - len); + return 1; + } + memcpy(sbuf, p, apdu.lc); + apdu.data = sbuf; + apdu.datalen = apdu.lc; + len -= apdu.lc; + p += apdu.lc; + if (len == 0) { + apdu.cse = SC_APDU_CASE_3_SHORT | cse; + } + else { + apdu.le = 0; + if (cse & SC_APDU_EXT) { + if (len < 2) { + printf("APDU too short (need %lu bytes)\n", + (unsigned long) apdu.lc - len); + return 1; + } + size = (*p++) << 8; + size += *p++; + len -= 2; + apdu.le = (size == 0) ? 65536 : size; + } + else { + size = *p++; + len--; + apdu.le = (size == 0) ? 256 : size; + } + apdu.cse = SC_APDU_CASE_4_SHORT | cse; + if (len) { + printf("APDU too long (%lu bytes extra)\n", + (unsigned long) len); + return 1; + } + } + } + } + printf("Sending: "); for (r = 0; r < len0; r++) printf("%02X ", buf[r]);