mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-06 13:11:18 -07:00
'hf 14a apdu' improvement
(PR 249 by @merlokk on https://github.com/RfidResearchGroup/proxmark3) * add option to print APDU (if it can be decoded) * add option to cconstruct extended and normal size APDUs
This commit is contained in:
parent
ca24170fd4
commit
5a446cb212
5 changed files with 581 additions and 281 deletions
|
@ -18,6 +18,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff)
|
- Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Added to `hf 14a apdu` print apdu and compose apdu (@merlokk)
|
||||||
- Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4)
|
- Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4)
|
||||||
- Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow)
|
- Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow)
|
||||||
- Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow)
|
- Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow)
|
||||||
|
|
|
@ -921,20 +921,34 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
|
||||||
int CmdHF14AAPDU(const char *cmd) {
|
int CmdHF14AAPDU(const char *cmd) {
|
||||||
uint8_t data[USB_CMD_DATA_SIZE];
|
uint8_t data[USB_CMD_DATA_SIZE];
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
|
uint8_t header[5];
|
||||||
|
int headerlen = 0;
|
||||||
bool activateField = false;
|
bool activateField = false;
|
||||||
bool leaveSignalON = false;
|
bool leaveSignalON = false;
|
||||||
bool decodeTLV = false;
|
bool decodeTLV = false;
|
||||||
|
bool decodeAPDU = false;
|
||||||
|
bool makeAPDU = false;
|
||||||
|
bool extendedAPDU = false;
|
||||||
|
int le = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
CLIParserInit("hf 14a apdu",
|
CLIParserInit("hf 14a apdu",
|
||||||
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)",
|
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). Works with all APDU types from ISO 7816-4:2013",
|
||||||
"Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n");
|
"Examples:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"
|
||||||
|
"\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode APDU\n"
|
||||||
|
"\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard APDU\n"
|
||||||
|
"\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended APDU\n");
|
||||||
|
|
||||||
void* argtable[] = {
|
void* argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("sS", "select", "activate field and select card"),
|
arg_lit0("sS", "select", "activate field and select card"),
|
||||||
arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
|
arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
|
||||||
arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
|
arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
|
||||||
arg_strx1(NULL, NULL, "<APDU (hex)>", NULL),
|
arg_lit0("dD", "decapdu", "decode APDU request if it possible"),
|
||||||
|
arg_str0("mM", "make", "<head (CLA INS P1 P2) hex>", "make APDU with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
|
||||||
|
arg_lit0("eE", "extended", "make extended length APDU (requires `-m`)"),
|
||||||
|
arg_int0("lL", "le", "<Le (int)>", "Le APDU parameter (requires `-m`)"),
|
||||||
|
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "APDU (without `-m`), or data (with `-m`)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(cmd, argtable, false);
|
CLIExecWithReturn(cmd, argtable, false);
|
||||||
|
@ -942,15 +956,71 @@ int CmdHF14AAPDU(const char *cmd) {
|
||||||
activateField = arg_get_lit(1);
|
activateField = arg_get_lit(1);
|
||||||
leaveSignalON = arg_get_lit(2);
|
leaveSignalON = arg_get_lit(2);
|
||||||
decodeTLV = arg_get_lit(3);
|
decodeTLV = arg_get_lit(3);
|
||||||
// len = data + PCB(1b) + CRC(2b)
|
decodeAPDU = arg_get_lit(4);
|
||||||
CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2);
|
|
||||||
|
|
||||||
|
res = CLIParamHexToBuf(arg_get_str(5), header, sizeof(header), &headerlen);
|
||||||
|
makeAPDU = headerlen > 0;
|
||||||
|
if (res || (makeAPDU && headerlen != 4)) {
|
||||||
|
PrintAndLogEx(ERR, "header length must be exactly 4 bytes");
|
||||||
|
CLIParserFree();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
extendedAPDU = arg_get_lit(6);
|
||||||
|
le = arg_get_int_def(7, 0);
|
||||||
|
|
||||||
|
if (makeAPDU) {
|
||||||
|
uint8_t apdudata[USB_CMD_DATA_SIZE] = {0};
|
||||||
|
int apdudatalen = 0;
|
||||||
|
|
||||||
|
CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2);
|
||||||
|
|
||||||
|
APDUStruct apdu;
|
||||||
|
apdu.cla = header[0];
|
||||||
|
apdu.ins = header[1];
|
||||||
|
apdu.p1 = header[2];
|
||||||
|
apdu.p2 = header[3];
|
||||||
|
|
||||||
|
apdu.lc = apdudatalen;
|
||||||
|
apdu.data = apdudata;
|
||||||
|
|
||||||
|
apdu.extended_apdu = extendedAPDU;
|
||||||
|
apdu.le = le;
|
||||||
|
|
||||||
|
if (APDUEncode(&apdu, data, &datalen)) {
|
||||||
|
PrintAndLogEx(ERR, "can't make apdu with provided parameters.");
|
||||||
|
CLIParserFree();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (extendedAPDU) {
|
||||||
|
PrintAndLogEx(ERR, "`-e` without `-m`.");
|
||||||
|
CLIParserFree();
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (le > 0) {
|
||||||
|
PrintAndLogEx(ERR, "`-l` without `-m`.");
|
||||||
|
CLIParserFree();
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// len = data + PCB(1b) + CRC(2b)
|
||||||
|
CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2);
|
||||||
|
}
|
||||||
|
|
||||||
CLIParserFree();
|
CLIParserFree();
|
||||||
// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]);
|
// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]);
|
||||||
PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
|
PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
|
||||||
|
|
||||||
int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
|
if (decodeAPDU) {
|
||||||
|
APDUStruct apdu;
|
||||||
|
|
||||||
|
if (APDUDecode(data, datalen, &apdu) == 0)
|
||||||
|
APDUPrint(apdu);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(WARNING, "can't decode APDU.");
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
#include "apduinfo.h"
|
#include "apduinfo.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
|
||||||
const APDUCode APDUCodeTable[] = {
|
const APDUCode APDUCodeTable[] = {
|
||||||
// ID Type Description
|
// ID Type Description
|
||||||
{"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string
|
{"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string
|
||||||
|
@ -132,11 +137,11 @@ const APDUCode APDUCodeTable[] = {
|
||||||
{"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"},
|
{"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"},
|
||||||
{"6F--", APDUCODE_TYPE_ERROR, "Internal exception"},
|
{"6F--", APDUCODE_TYPE_ERROR, "Internal exception"},
|
||||||
{"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."},
|
{"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."},
|
||||||
{"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse, ...)"},
|
{"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse)"},
|
||||||
{"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"},
|
{"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"},
|
||||||
{"9---", APDUCODE_TYPE_NONE, ""},
|
{"9---", APDUCODE_TYPE_NONE, ""},
|
||||||
{"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."},
|
{"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."},
|
||||||
{"9004", APDUCODE_TYPE_WARNING, "PIN not succesfully verified, 3 or more PIN tries left"},
|
{"9004", APDUCODE_TYPE_WARNING, "PIN not successfully verified, 3 or more PIN tries left"},
|
||||||
{"9008", APDUCODE_TYPE_NONE, "Key/file not found"},
|
{"9008", APDUCODE_TYPE_NONE, "Key/file not found"},
|
||||||
{"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"},
|
{"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"},
|
||||||
{"9100", APDUCODE_TYPE_NONE, "OK"},
|
{"9100", APDUCODE_TYPE_NONE, "OK"},
|
||||||
|
@ -184,7 +189,7 @@ const APDUCode APDUCodeTable[] = {
|
||||||
{"9681", APDUCODE_TYPE_NONE, "Slave not found"},
|
{"9681", APDUCODE_TYPE_NONE, "Slave not found"},
|
||||||
{"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"},
|
{"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"},
|
||||||
{"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"},
|
{"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"},
|
||||||
{"9704", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 3 or more PIN tries left"},
|
{"9704", APDUCODE_TYPE_NONE, "PIN not successfully verified, 3 or more PIN tries left"},
|
||||||
{"9784", APDUCODE_TYPE_NONE, "Base key"},
|
{"9784", APDUCODE_TYPE_NONE, "Base key"},
|
||||||
{"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"},
|
{"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"},
|
||||||
{"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"},
|
{"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"},
|
||||||
|
@ -198,13 +203,13 @@ const APDUCode APDUCodeTable[] = {
|
||||||
{"9850", APDUCODE_TYPE_ERROR, "INCREASE or DECREASE could not be executed because a limit has been reached."},
|
{"9850", APDUCODE_TYPE_ERROR, "INCREASE or DECREASE could not be executed because a limit has been reached."},
|
||||||
{"9862", APDUCODE_TYPE_ERROR, "Authentication Error, application specific (incorrect MAC)"},
|
{"9862", APDUCODE_TYPE_ERROR, "Authentication Error, application specific (incorrect MAC)"},
|
||||||
{"9900", APDUCODE_TYPE_NONE, "1 PIN try left"},
|
{"9900", APDUCODE_TYPE_NONE, "1 PIN try left"},
|
||||||
{"9904", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 1 PIN try left"},
|
{"9904", APDUCODE_TYPE_NONE, "PIN not successfully verified, 1 PIN try left"},
|
||||||
{"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"},
|
{"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"},
|
||||||
{"9986", APDUCODE_TYPE_ERROR, "Missing privilege"},
|
{"9986", APDUCODE_TYPE_ERROR, "Missing privilege"},
|
||||||
{"9987", APDUCODE_TYPE_NONE, "PIN is not installed"},
|
{"9987", APDUCODE_TYPE_NONE, "PIN is not installed"},
|
||||||
{"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"},
|
{"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"},
|
||||||
{"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"},
|
{"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"},
|
||||||
{"9A04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 2 PIN try left"},
|
{"9A04", APDUCODE_TYPE_NONE, "PIN not successfully verified, 2 PIN try left"},
|
||||||
{"9A71", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent AID"},
|
{"9A71", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent AID"},
|
||||||
{"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"},
|
{"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"},
|
||||||
{"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"},
|
{"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"},
|
||||||
|
@ -251,15 +256,15 @@ const APDUCode APDUCodeTable[] = {
|
||||||
{"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"},
|
{"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"},
|
||||||
{"9D64", APDUCODE_TYPE_ERROR, "No application loaded"},
|
{"9D64", APDUCODE_TYPE_ERROR, "No application loaded"},
|
||||||
{"9E00", APDUCODE_TYPE_NONE, "PIN not installed"},
|
{"9E00", APDUCODE_TYPE_NONE, "PIN not installed"},
|
||||||
{"9E04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, PIN not installed"},
|
{"9E04", APDUCODE_TYPE_NONE, "PIN not successfully verified, PIN not installed"},
|
||||||
{"9F00", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 3"},
|
{"9F00", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 3"},
|
||||||
{"9F04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, PIN blocked and Unblock Try Counter is 3"},
|
{"9F04", APDUCODE_TYPE_NONE, "PIN not successfully verified, PIN blocked and Unblock Try Counter is 3"},
|
||||||
{"9FXX", APDUCODE_TYPE_NONE, "Command successfully executed; 'xx' bytes of data are available and can be requested using GET RESPONSE."},
|
{"9FXX", APDUCODE_TYPE_NONE, "Command successfully executed; 'xx' bytes of data are available and can be requested using GET RESPONSE."},
|
||||||
{"9XXX", APDUCODE_TYPE_NONE, "Application related status, (ISO 7816-3)"}
|
{"9XXX", APDUCODE_TYPE_NONE, "Application related status, (ISO 7816-3)"}
|
||||||
};
|
};
|
||||||
const size_t APDUCodeTableLen = sizeof(APDUCodeTable)/sizeof(APDUCode);
|
const size_t APDUCodeTableLen = sizeof(APDUCodeTable) / sizeof(APDUCode);
|
||||||
|
|
||||||
int CodeCmp(const char *code1, const char *code2) {
|
static int CodeCmp(const char *code1, const char *code2) {
|
||||||
int xsymb = 0;
|
int xsymb = 0;
|
||||||
int cmp = 0;
|
int cmp = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
@ -277,16 +282,15 @@ int CodeCmp(const char *code1, const char *code2) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) {
|
const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2) {
|
||||||
char buf[5] = {0};
|
char buf[6] = {0};
|
||||||
int res;
|
|
||||||
int mineq = APDUCodeTableLen;
|
int mineq = APDUCodeTableLen;
|
||||||
int mineqindx = 0;
|
int mineqindx = 0;
|
||||||
|
|
||||||
sprintf(buf, "%02X%02X", sw1, sw2);
|
sprintf(buf, "%02X%02X", sw1, sw2);
|
||||||
|
|
||||||
for (int i = 0; i < APDUCodeTableLen; i++) {
|
for (int i = 0; i < APDUCodeTableLen; i++) {
|
||||||
res = CodeCmp(APDUCodeTable[i].ID, buf);
|
int res = CodeCmp(APDUCodeTable[i].ID, buf);
|
||||||
|
|
||||||
// equal
|
// equal
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
|
@ -308,10 +312,197 @@ const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) {
|
const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) {
|
||||||
const APDUCode *cd = GetAPDUCode(sw1, sw2);
|
const APDUCode *cd = GetAPDUCode(sw1, sw2);
|
||||||
if (cd)
|
if (cd)
|
||||||
return cd->Description;
|
return cd->Description;
|
||||||
else
|
else
|
||||||
return APDUCodeTable[0].Description; //empty string
|
return APDUCodeTable[0].Description; //empty string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int APDUDecode(uint8_t *data, int len, APDUStruct *apdu) {
|
||||||
|
ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data;
|
||||||
|
|
||||||
|
apdu->cla = hapdu->cla;
|
||||||
|
apdu->ins = hapdu->ins;
|
||||||
|
apdu->p1 = hapdu->p1;
|
||||||
|
apdu->p2 = hapdu->p2;
|
||||||
|
|
||||||
|
apdu->lc = 0;
|
||||||
|
apdu->data = NULL;
|
||||||
|
apdu->le = 0;
|
||||||
|
apdu->extended_apdu = false;
|
||||||
|
apdu->case_type = 0x00;
|
||||||
|
|
||||||
|
uint8_t b0 = hapdu->lc[0];
|
||||||
|
|
||||||
|
// case 1
|
||||||
|
if (len == 4) {
|
||||||
|
apdu->case_type = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2S (Le)
|
||||||
|
if (len == 5) {
|
||||||
|
apdu->case_type = 0x02;
|
||||||
|
apdu->le = b0;
|
||||||
|
if (!apdu->le)
|
||||||
|
apdu->le = 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 3S (Lc + data)
|
||||||
|
if (len == 5U + b0 && b0 != 0) {
|
||||||
|
apdu->case_type = 0x03;
|
||||||
|
apdu->lc = b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4S (Lc + data + Le)
|
||||||
|
if (len == 5U + b0 + 1U && b0 != 0) {
|
||||||
|
apdu->case_type = 0x04;
|
||||||
|
apdu->lc = b0;
|
||||||
|
apdu->le = data[len - 1];
|
||||||
|
if (!apdu->le)
|
||||||
|
apdu->le = 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extended length apdu
|
||||||
|
if (len >= 7 && b0 == 0) {
|
||||||
|
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
|
||||||
|
|
||||||
|
// case 2E (Le) - extended
|
||||||
|
if (len == 7) {
|
||||||
|
apdu->case_type = 0x12;
|
||||||
|
apdu->extended_apdu = true;
|
||||||
|
apdu->le = extlen;
|
||||||
|
if (!apdu->le)
|
||||||
|
apdu->le = 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 3E (Lc + data) - extended
|
||||||
|
if (len == 7U + extlen) {
|
||||||
|
apdu->case_type = 0x13;
|
||||||
|
apdu->extended_apdu = true;
|
||||||
|
apdu->lc = extlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4E (Lc + data + Le) - extended 2-byte Le
|
||||||
|
if (len == 7U + extlen + 2U) {
|
||||||
|
apdu->case_type = 0x14;
|
||||||
|
apdu->extended_apdu = true;
|
||||||
|
apdu->lc = extlen;
|
||||||
|
apdu->le = (data[len - 2] << 8) + data[len - 1];
|
||||||
|
if (!apdu->le)
|
||||||
|
apdu->le = 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4E (Lc + data + Le) - extended 3-byte Le
|
||||||
|
if (len == 7U + extlen + 3U && data[len - 3] == 0) {
|
||||||
|
apdu->case_type = 0x24;
|
||||||
|
apdu->extended_apdu = true;
|
||||||
|
apdu->lc = extlen;
|
||||||
|
apdu->le = (data[len - 2] << 8) + data[len - 1];
|
||||||
|
if (!apdu->le)
|
||||||
|
apdu->le = 0x10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!apdu->case_type)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (apdu->lc) {
|
||||||
|
if (apdu->extended_apdu) {
|
||||||
|
apdu->data = data + 7;
|
||||||
|
} else {
|
||||||
|
apdu->data = data + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) {
|
||||||
|
if (len)
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
if (apdu->le > 0x10000 || apdu->lc > 0xffff)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
size_t dptr = 0;
|
||||||
|
data[dptr++] = apdu->cla;
|
||||||
|
data[dptr++] = apdu->ins;
|
||||||
|
data[dptr++] = apdu->p1;
|
||||||
|
data[dptr++] = apdu->p2;
|
||||||
|
|
||||||
|
if (apdu->lc) {
|
||||||
|
if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0x100) {
|
||||||
|
data[dptr++] = 0x00;
|
||||||
|
data[dptr++] = (apdu->lc >> 8) & 0xff;
|
||||||
|
data[dptr++] = (apdu->lc) & 0xff;
|
||||||
|
memmove(&data[dptr], apdu->data, apdu->lc);
|
||||||
|
dptr += apdu->lc;
|
||||||
|
apdu->extended_apdu = true;
|
||||||
|
} else {
|
||||||
|
data[dptr++] = apdu->lc;
|
||||||
|
memmove(&data[dptr], apdu->data, apdu->lc);
|
||||||
|
dptr += apdu->lc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apdu->le) {
|
||||||
|
if (apdu->extended_apdu) {
|
||||||
|
if (apdu->le != 0x10000) {
|
||||||
|
data[dptr++] = 0x00;
|
||||||
|
data[dptr++] = (apdu->le >> 8) & 0xff;
|
||||||
|
data[dptr++] = (apdu->le) & 0xff;
|
||||||
|
} else {
|
||||||
|
data[dptr++] = 0x00;
|
||||||
|
data[dptr++] = 0x00;
|
||||||
|
data[dptr++] = 0x00;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (apdu->le != 0x100)
|
||||||
|
data[dptr++] = apdu->le;
|
||||||
|
else
|
||||||
|
data[dptr++] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
*len = dptr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *len) {
|
||||||
|
if (extended && le > 0x100)
|
||||||
|
return 10;
|
||||||
|
|
||||||
|
APDUStruct apdu;
|
||||||
|
|
||||||
|
apdu.cla = sapdu->CLA;
|
||||||
|
apdu.ins = sapdu->INS;
|
||||||
|
apdu.p1 = sapdu->P1;
|
||||||
|
apdu.p2 = sapdu->P2;
|
||||||
|
|
||||||
|
apdu.lc = sapdu->Lc;
|
||||||
|
if (sapdu->Lc)
|
||||||
|
apdu.data = sapdu->data;
|
||||||
|
else
|
||||||
|
apdu.data = NULL;
|
||||||
|
apdu.le = le;
|
||||||
|
|
||||||
|
apdu.extended_apdu = extended;
|
||||||
|
apdu.case_type = 0x00;
|
||||||
|
|
||||||
|
return APDUEncode(&apdu, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APDUPrint(APDUStruct apdu) {
|
||||||
|
APDUPrintEx(apdu, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) {
|
||||||
|
PrintAndLogEx(INFO, "APDU: %scase=0x%02x cla=0x%02x ins=0x%02x p1=0x%02x p2=0x%02x Lc=0x%02x(%d) Le=0x%02x(%d)",
|
||||||
|
apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.lc, apdu.le, apdu.le);
|
||||||
|
if (maxdatalen > 0)
|
||||||
|
PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : "");
|
||||||
|
}
|
||||||
|
|
|
@ -11,10 +11,8 @@
|
||||||
#ifndef APDUINFO_H__
|
#ifndef APDUINFO_H__
|
||||||
#define APDUINFO_H__
|
#define APDUINFO_H__
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "util.h"
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#define APDUCODE_TYPE_NONE 0
|
#define APDUCODE_TYPE_NONE 0
|
||||||
#define APDUCODE_TYPE_INFO 1
|
#define APDUCODE_TYPE_INFO 1
|
||||||
|
@ -28,7 +26,41 @@ typedef struct {
|
||||||
const char *Description;
|
const char *Description;
|
||||||
} APDUCode;
|
} APDUCode;
|
||||||
|
|
||||||
extern const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2);
|
typedef struct {
|
||||||
extern const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2);
|
uint8_t CLA;
|
||||||
|
uint8_t INS;
|
||||||
|
uint8_t P1;
|
||||||
|
uint8_t P2;
|
||||||
|
uint8_t Lc;
|
||||||
|
uint8_t *data;
|
||||||
|
} PACKED sAPDU;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t cla;
|
||||||
|
uint8_t ins;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
uint8_t lc[3];
|
||||||
|
} PACKED ExtAPDUHeader;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t cla;
|
||||||
|
uint8_t ins;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
uint16_t lc;
|
||||||
|
uint8_t *data;
|
||||||
|
uint32_t le;
|
||||||
|
bool extended_apdu;
|
||||||
|
uint8_t case_type;
|
||||||
|
} PACKED APDUStruct;
|
||||||
|
|
||||||
|
extern const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2);
|
||||||
|
extern const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2);
|
||||||
|
extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu);
|
||||||
|
extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len);
|
||||||
|
extern int APDUEncodeS(sAPDU *apdu, bool extended, uint16_t le, uint8_t *data, int *len);
|
||||||
|
extern void APDUPrint(APDUStruct apdu);
|
||||||
|
extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define PACKED
|
||||||
|
#else
|
||||||
|
#define PACKED __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ROTR
|
#ifndef ROTR
|
||||||
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
|
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue